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)
29 import os, sys, datetime, shutil, string
34 # directories not considered as test modules
35 C_IGNORE_MODULES = ['.git', '.svn', 'RESSOURCES']
37 C_TESTS_LIGHT_FILE = "TestsLight.txt"
39 # Get directory to be used for the temporary files.
41 def getTmpDirDEFAULT():
42 if src.architecture.is_windows():
43 directory = os.getenv("TEMP")
45 # for Linux: use /tmp/logs/{user} folder
46 directory = os.path.join( '/tmp', 'logs', os.getenv("USER", "unknown"))
62 self.modules = modules
65 self.sessionDir = sessionDir
70 self.show_desktop = show_desktop
74 self.logger.write("\n", 3, False)
75 self.prepare_grid_from_dir("DIR", self.dir)
76 self.currentGrid = "DIR"
78 self.prepare_grid(grid)
81 self.known_errors = None
83 # create section for results
84 self.config.TESTS = src.pyconf.Sequence(self.config)
90 self.nb_acknoledge = 0
92 def _copy_dir(self, source, target):
93 if self.config.VARS.python >= "2.6":
94 shutil.copytree(source, target,
96 ignore=shutil.ignore_patterns('.git*','.svn*'))
98 shutil.copytree(source, target,
101 def prepare_grid_from_dir(self, grid_name, grid_dir):
102 self.logger.write(_("get grid from dir: %s\n") % \
103 src.printcolors.printcLabel(grid_dir), 3)
104 if not os.access(grid_dir, os.X_OK):
105 raise src.SatException(_("testbase %(name)s (%(dir)s) does not "
106 "exist ...\n") % { 'name': grid_name,
109 self._copy_dir(grid_dir,
110 os.path.join(self.sessionDir, 'BASES', grid_name))
112 def prepare_grid_from_git(self, grid_name, grid_base, grid_tag):
114 _("get grid '%(grid)s' with '%(tag)s' tag from git\n") % {
115 "grid" : src.printcolors.printcLabel(grid_name),
116 "tag" : src.printcolors.printcLabel(grid_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 grid_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': grid_tag,
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.sessionDir, 'BASES'),
141 stdout=self.logger.logTxtFile,
142 stderr=subprocess.PIPE)
144 res = subprocess.call(cmd,
145 cwd=os.path.join(self.sessionDir, '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': grid_name, 'repo': grid_base })
156 self.logger.error(_("git is not installed. exiting...\n"))
159 def prepare_grid_from_svn(self, user, grid_name, grid_base):
160 self.logger.write(_("get grid '%s' from svn\n") % \
161 src.printcolors.printcLabel(grid_name), 3)
163 def set_signal(): # pragma: no cover
164 """see http://bugs.python.org/issue1652"""
166 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
168 cmd = "svn checkout --username %(user)s %(base)s %(dir)s"
169 cmd = cmd % { 'user': user, 'base': grid_base, 'dir': grid_name }
171 self.logger.write("> %s\n" % cmd, 5)
172 if src.architecture.is_windows():
173 # preexec_fn not supported on windows platform
174 res = subprocess.call(cmd,
175 cwd=os.path.join(self.sessionDir, 'BASES'),
177 stdout=self.logger.logTxtFile,
178 stderr=subprocess.PIPE)
180 res = subprocess.call(cmd,
181 cwd=os.path.join(self.sessionDir, 'BASES'),
183 preexec_fn=set_signal,
184 stdout=self.logger.logTxtFile,
185 stderr=subprocess.PIPE)
188 raise src.SatException(_("Error: unable to get test base '%(nam"
189 "e)s' from svn '%(repo)s'.") % \
190 { 'name': grid_name, 'repo': grid_base })
193 self.logger.error(_("svn is not installed. exiting...\n"))
197 # Configure tests base.
198 def prepare_grid(self, grid_name):
199 src.printcolors.print_value(self.logger,
203 self.logger.write("\n", 3, False)
205 # search for the grid
206 test_base_info = None
207 for project_name in self.config.PROJECTS.projects:
208 project_info = self.config.PROJECTS.projects[project_name]
209 for t_b_info in project_info.test_bases:
210 if t_b_info.name == grid_name:
211 test_base_info = t_b_info
213 if not test_base_info:
214 message = _("########## WARNING: grid '%s' not found\n") % grid_name
215 raise src.SatException(message)
217 if test_base_info.get_sources == "dir":
218 self.prepare_grid_from_dir(grid_name, test_base_info.info.dir)
219 elif test_base_info.get_sources == "git":
220 self.prepare_grid_from_git(grid_name,
221 test_base_info.info.base,
222 self.config.APPLICATION.test_base.tag)
223 elif test_base_info.get_sources == "svn":
224 svn_user = src.get_cfg_param(test_base_info.svn_info,
226 self.config.USER.svn_user)
227 self.prepare_grid_from_svn(svn_user,
229 test_base_info.info.base)
231 raise src.SatException(_("unknown source type '%(type)s' for testb"
232 "ase '%(grid)s' ...\n") % {
233 'type': test_base_info.get_sources,
236 self.currentGrid = grid_name
239 # Searches if the script is declared in known errors pyconf.
240 # Update the status if needed.
241 def search_known_errors(self, status, test_module, test_type, test):
242 test_path = os.path.join(test_module, test_type, test)
243 if not src.config_has_application(self.config):
246 if self.known_errors is None:
249 platform = self.config.VARS.arch
250 application = self.config.VARS.application
251 error = self.known_errors.get_error(test_path, application, platform)
255 if status == src.OK_STATUS:
258 self.known_errors.fix_error(error)
260 #testerror.write_test_failures(
261 # self.config.TOOLS.testerror.file_path,
262 # self.known_errors.errors)
263 return status, [ error.date,
269 self.known_errors.unfix_error(error)
271 #testerror.write_test_failures(self.config.TOOLS.testerror.file_path,
272 # self.known_errors.errors)
274 delta = self.known_errors.get_expecting_days(error)
275 kfres = [ error.date, error.expected, error.comment, error.fixed ]
277 return src.KO_STATUS, kfres
278 return src.KNOWNFAILURE_STATUS, kfres
281 # Read the *.result.py files.
282 def read_results(self, listTest, has_timed_out):
284 for test in listTest:
285 resfile = os.path.join(self.currentDir,
288 test[:-3] + ".result.py")
290 # check if <test>.result.py file exists
291 if not os.path.exists(resfile):
292 results[test] = ["?", -1, "", []]
295 execfile(resfile, gdic, ldic)
297 status = src.TIMEOUT_STATUS
298 if not has_timed_out:
299 status = src.KO_STATUS
301 if ldic.has_key('status'):
302 status = ldic['status']
305 if status == src.KO_STATUS or status == src.OK_STATUS:
306 status, expected = self.search_known_errors(status,
312 if ldic.has_key('callback'):
313 callback = ldic['callback']
314 elif status == src.KO_STATUS:
318 if ldic.has_key('time'):
320 exec_time = float(ldic['time'])
324 results[test] = [status, exec_time, callback, expected]
326 # check if <test>.py file exists
327 testfile = os.path.join(self.currentDir,
332 if not os.path.exists(testfile):
333 results[test].append('')
335 text = open(testfile, "r").read()
336 results[test].append(text)
338 # check if <test>.out.py file exists
339 outfile = os.path.join(self.currentDir,
342 test[:-3] + ".out.py")
344 if not os.path.exists(outfile):
345 results[test].append('')
347 text = open(outfile, "r").read()
348 results[test].append(text)
353 # Generates the script to be run by Salome.
354 # This python script includes init and close statements and a loop
355 # calling all the scripts of a single directory.
356 def generate_script(self, listTest, script_path, ignoreList):
358 template_file = open(os.path.join(self.config.VARS.srcDir,
360 "scriptTemplate.py"), 'r')
361 template = string.Template(template_file.read())
363 # create substitution dictionary
365 d['resourcesWay'] = os.path.join(self.currentDir, 'RESSOURCES')
366 d['tmpDir'] = os.path.join(self.sessionDir, 'WORK')
367 d['toolsWay'] = os.path.join(self.config.VARS.srcDir, "test")
368 d['typeDir'] = os.path.join(self.currentDir,
371 d['resultFile'] = os.path.join(self.sessionDir, 'WORK', 'exec_result')
372 d['listTest'] = listTest
373 d['typeName'] = self.currentType
374 d['ignore'] = ignoreList
376 # create script with template
377 script = open(script_path, 'w')
378 script.write(template.safe_substitute(d))
381 # Find the getTmpDir function that gives access to *pidict file directory.
382 # (the *pidict file exists when SALOME is launched)
383 def get_tmp_dir(self):
384 # Rare case where there is no KERNEL in module list
385 # (for example MED_STANDALONE)
386 if ('APPLICATION' in self.config
387 and 'KERNEL' not in self.config.APPLICATION.products
388 and 'KERNEL_ROOT_DIR' not in os.environ):
389 return getTmpDirDEFAULT
391 # Case where "sat test" is launched in an existing SALOME environment
392 if 'KERNEL_ROOT_DIR' in os.environ:
393 root_dir = os.environ['KERNEL_ROOT_DIR']
395 if ('APPLICATION' in self.config
396 and 'KERNEL' in self.config.APPLICATION.products):
397 root_dir = src.product.get_product_config(self.config,
398 "KERNEL").install_dir
400 # Case where there the appli option is called (with path to launcher)
401 if len(self.appli) > 0:
402 # There are two cases : The old application (runAppli)
404 launcherName = os.path.basename(self.appli)
405 launcherDir = os.path.dirname(self.appli)
406 if launcherName == 'runAppli':
408 cmd = "for i in " + launcherDir + "/env.d/*.sh; do source ${i};"
409 " done ; echo $KERNEL_ROOT_DIR"
412 cmd = "echo -e 'import os\nprint os.environ[\"KERNEL_ROOT_DIR\""
413 "]' > tmpscript.py; %s shell tmpscript.py" % self.appli
414 root_dir = subprocess.Popen(cmd,
415 stdout=subprocess.PIPE,
417 executable='/bin/bash').communicate()[0].split()[-1]
419 # import module salome_utils from KERNEL that gives
420 # the right getTmpDir function
422 (file_, pathname, description) = imp.find_module("salome_utils",
423 [os.path.join(root_dir,
427 module = imp.load_module("salome_utils",
431 return module.getLogDir
433 module = imp.load_module("salome_utils",
437 return module.getTmpDir
443 def get_test_timeout(self, test_name, default_value):
444 if ("timeout" in self.settings and
445 test_name in self.settings["timeout"]):
446 return self.settings["timeout"][test_name]
450 def generate_launching_commands(self, typename):
451 # Case where "sat test" is launched in an existing SALOME environment
452 if 'KERNEL_ROOT_DIR' in os.environ:
453 binSalome = "runSalome"
455 killSalome = "killSalome.py"
457 # Rare case where there is no KERNEL in module list
458 # (for example MED_STANDALONE)
459 if ('APPLICATION' in self.config and
460 'KERNEL' not in self.config.APPLICATION.products):
461 binSalome = "runSalome"
463 killSalome = "killSalome.py"
464 src.environment.load_environment(self.config, False, self.logger)
465 return binSalome, binPython, killSalome
467 # Case where there the appli option is called (with path to launcher)
468 if len(self.appli) > 0:
469 # There are two cases : The old application (runAppli)
471 launcherName = os.path.basename(self.appli)
472 launcherDir = os.path.dirname(self.appli)
473 if launcherName == 'runAppli':
475 binSalome = self.appli
476 binPython = ("for i in " +
478 "/env.d/*.sh; do source ${i}; done ; python")
479 killSalome = ("for i in " +
481 "/env.d/*.sh; do source ${i}; done ; killSalome.py'")
482 return binSalome, binPython, killSalome
485 binSalome = self.appli
486 binPython = self.appli + ' context'
487 killSalome = self.appli + ' killall'
488 return binSalome, binPython, killSalome
490 # SALOME version detection and APPLI repository detection
491 VersionSalome = src.get_salome_version(self.config)
493 if "APPLI" in self.config and "application_name" in self.config.APPLI:
494 appdir = self.config.APPLI.application_name
496 # Case where SALOME has NOT the launcher that uses the SalomeContext API
497 if VersionSalome < 730:
498 binSalome = os.path.join(self.config.APPLI.module_appli_install_dir,
502 killSalome = "killSalome.py"
503 src.environment.load_environment(self.config, False, self.logger)
504 return binSalome, binPython, killSalome
506 # Case where SALOME has the launcher that uses the SalomeContext API
507 if VersionSalome >= 730:
508 if 'profile' not in self.config.APPLICATION:
509 # Before revision of application concept
510 launcher_name = self.config.APPLI.launch_alias_name
511 binSalome = os.path.join(self.config.APPLICATION.workdir,
515 # After revision of application concept
516 launcher_name = self.config.APPLICATION.profile.launcher_name
517 binSalome = os.path.join(self.config.APPLICATION.workdir,
520 if src.architecture.is_windows():
523 binPython = binSalome + ' context'
524 killSalome = binSalome + ' killall'
525 return binSalome, binPython, killSalome
527 return binSalome, binPython, killSalome
531 # Runs tests of a type (using a single instance of Salome).
532 def run_tests(self, listTest, ignoreList):
533 out_path = os.path.join(self.currentDir,
536 typename = "%s/%s" % (self.currentModule, self.currentType)
537 time_out = self.get_test_timeout(typename,
538 self.config.SITE.test.timeout)
540 time_out_salome = src.get_cfg_param(self.config.SITE.test,
542 self.config.SITE.test.timeout)
544 # generate wrapper script
545 script_path = os.path.join(out_path, 'wrapperScript.py')
546 self.generate_script(listTest, script_path, ignoreList)
548 tmpDir = self.get_tmp_dir()
550 binSalome, binPython, killSalome = self.generate_launching_commands(
552 if self.settings.has_key("run_with_modules") \
553 and self.settings["run_with_modules"].has_key(typename):
554 binSalome = (binSalome +
555 " -m %s" % self.settings["run_with_modules"][typename])
557 logWay = os.path.join(self.sessionDir, "WORK", "log_cxx")
561 if self.currentType.startswith("NOGUI_"):
562 # runSalome -t (bash)
563 status, ellapsed = fork.batch(binSalome, self.logger,
564 os.path.join(self.sessionDir, "WORK"),
566 "--shutdown-server=1",
571 elif self.currentType.startswith("PY_"):
573 status, ellapsed = fork.batch(binPython, self.logger,
574 os.path.join(self.sessionDir, "WORK"),
576 delai=time_out, log=logWay)
580 if self.show_desktop: opt = "--show-desktop=0"
581 status, ellapsed = fork.batch_salome(binSalome,
583 os.path.join(self.sessionDir,
586 "--shutdown-server=1",
592 delaiapp=time_out_salome)
594 self.logger.write("status = %s, ellapsed = %s\n" % (status, ellapsed),
597 # create the test result to add in the config object
598 test_info = src.pyconf.Mapping(self.config)
599 test_info.grid = self.currentGrid
600 test_info.module = self.currentModule
601 test_info.type = self.currentType
602 test_info.script = src.pyconf.Sequence(self.config)
604 script_results = self.read_results(listTest, ellapsed == time_out)
605 for sr in sorted(script_results.keys()):
608 # create script result
609 script_info = src.pyconf.Mapping(self.config)
610 script_info.name = sr
611 script_info.res = script_results[sr][0]
612 script_info.time = script_results[sr][1]
613 if script_info.res == src.TIMEOUT_STATUS:
614 script_info.time = time_out
615 if script_info.time < 1e-3: script_info.time = 0
617 callback = script_results[sr][2]
618 if script_info.res != src.OK_STATUS and len(callback) > 0:
619 script_info.callback = callback
621 kfres = script_results[sr][3]
623 script_info.known_error = src.pyconf.Mapping(self.config)
624 script_info.known_error.date = kfres[0]
625 script_info.known_error.expected = kfres[1]
626 script_info.known_error.comment = kfres[2]
627 script_info.known_error.fixed = kfres[3]
629 script_info.content = script_results[sr][4]
630 script_info.out = script_results[sr][5]
632 # add it to the list of results
633 test_info.script.append(script_info, '')
635 # display the results
636 if script_info.time > 0:
637 exectime = "(%7.3f s)" % script_info.time
641 sp = "." * (35 - len(script_info.name))
642 self.logger.write(self.write_test_margin(3), 3)
643 self.logger.write("script %s %s %s %s\n" % (
644 src.printcolors.printcLabel(script_info.name),
646 src.printcolors.printc(script_info.res),
648 if script_info and len(callback) > 0:
649 self.logger.write("Exception in %s\n%s\n" % \
651 src.printcolors.printcWarning(callback)), 2, False)
653 if script_info.res == src.OK_STATUS:
655 elif script_info.res == src.KNOWNFAILURE_STATUS:
656 self.nb_acknoledge += 1
657 elif script_info.res == src.TIMEOUT_STATUS:
659 elif script_info.res == src.NA_STATUS:
661 elif script_info.res == "?":
664 self.config.TESTS.append(test_info, '')
667 # Runs all tests of a type.
668 def run_type_tests(self, light_test):
670 if not any(map(lambda l: l.startswith(self.currentType),
672 # no test to run => skip
675 self.logger.write(self.write_test_margin(2), 3)
676 self.logger.write("Type = %s\n" % src.printcolors.printcLabel(
677 self.currentType), 3, False)
679 # prepare list of tests to run
680 tests = os.listdir(os.path.join(self.currentDir,
683 tests = filter(lambda l: l.endswith(".py"), tests)
684 tests = sorted(tests, key=str.lower)
687 tests = filter(lambda l: os.path.join(self.currentType,
688 l) in light_test, tests)
690 # build list of known failures
691 cat = "%s/%s/" % (self.currentModule, self.currentType)
693 for k in self.ignore_tests.keys():
694 if k.startswith(cat):
695 ignoreDict[k[len(cat):]] = self.ignore_tests[k]
697 self.run_tests(tests, ignoreDict)
700 # Runs all tests of a module.
701 def run_module_tests(self):
702 self.logger.write(self.write_test_margin(1), 3)
703 self.logger.write("Module = %s\n" % src.printcolors.printcLabel(
704 self.currentModule), 3, False)
706 module_path = os.path.join(self.currentDir, self.currentModule)
709 if self.types is not None:
710 types = self.types # user choice
712 # use all scripts in module
713 types = filter(lambda l: l not in C_IGNORE_MODULES,
714 os.listdir(module_path))
715 types = filter(lambda l: os.path.isdir(os.path.join(module_path,
718 # in batch mode keep only modules with NOGUI or PY
719 if self.mode == "batch":
720 types = filter(lambda l: ("NOGUI" in l or "PY" in l), types)
724 light_path = os.path.join(module_path, C_TESTS_LIGHT_FILE)
725 if not os.path.exists(light_path):
727 msg = src.printcolors.printcWarning(_("List of light tests not"
728 " found: %s") % light_path)
729 self.logger.write(msg + "\n")
732 light_file = open(light_path, "r")
733 light_test = map(lambda l: l.strip(), light_file.readlines())
735 types = sorted(types, key=str.lower)
737 if not os.path.exists(os.path.join(module_path, type_)):
738 self.logger.write(self.write_test_margin(2), 3)
739 self.logger.write(src.printcolors.printcWarning("Type %s not "
740 "found" % type_) + "\n", 3, False)
742 self.currentType = type_
743 self.run_type_tests(light_test)
747 def run_grid_tests(self):
748 res_dir = os.path.join(self.currentDir, "RESSOURCES")
749 os.environ['PYTHONPATH'] = (res_dir +
751 os.environ['PYTHONPATH'])
752 os.environ['TT_BASE_RESSOURCES'] = res_dir
753 src.printcolors.print_value(self.logger,
754 "TT_BASE_RESSOURCES",
757 self.logger.write("\n", 4, False)
759 self.logger.write(self.write_test_margin(0), 3)
760 grid_label = "Grid = %s\n" % src.printcolors.printcLabel(
762 self.logger.write(grid_label, 3, False)
763 self.logger.write("-" * len(src.printcolors.cleancolor(grid_label)), 3)
764 self.logger.write("\n", 3, False)
767 settings_file = os.path.join(res_dir, "test_settings.py")
768 if os.path.exists(settings_file):
770 execfile(settings_file, gdic, ldic)
771 self.logger.write(_("Load test settings\n"), 3)
772 self.settings = ldic['settings_dic']
773 self.ignore_tests = ldic['known_failures_list']
774 if isinstance(self.ignore_tests, list):
775 self.ignore_tests = {}
776 self.logger.write(src.printcolors.printcWarning("known_failur"
777 "es_list must be a dictionary (not a list)") + "\n", 1, False)
779 self.ignore_tests = {}
780 self.settings.clear()
782 # read known failures pyconf
783 if "testerror" in self.config.SITE:
785 #self.known_errors = testerror.read_test_failures(
786 # self.config.TOOLS.testerror.file_path,
790 self.known_errors = None
792 if self.modules is not None:
793 modules = self.modules # given by user
795 # select all the modules (i.e. directories) in the directory
796 modules = filter(lambda l: l not in C_IGNORE_MODULES,
797 os.listdir(self.currentDir))
798 modules = filter(lambda l: os.path.isdir(
799 os.path.join(self.currentDir, l)),
802 modules = sorted(modules, key=str.lower)
803 for module in modules:
804 if not os.path.exists(os.path.join(self.currentDir, module)):
805 self.logger.write(self.write_test_margin(1), 3)
806 self.logger.write(src.printcolors.printcWarning(
807 "Module %s does not exist\n" % module), 3, False)
809 self.currentModule = module
810 self.run_module_tests()
812 def run_script(self, script_name):
813 if 'APPLICATION' in self.config and script_name in self.config.APPLICATION:
814 script = self.config.APPLICATION[script_name]
818 self.logger.write("\n", 2, False)
819 if not os.path.exists(script):
820 self.logger.write(src.printcolors.printcWarning("WARNING: scrip"
821 "t not found: %s" % script) + "\n", 2)
823 self.logger.write(src.printcolors.printcHeader("----------- sta"
824 "rt %s" % script_name) + "\n", 2)
825 self.logger.write("Run script: %s\n" % script, 2)
826 subprocess.Popen(script, shell=True).wait()
827 self.logger.write(src.printcolors.printcHeader("----------- end"
828 " %s" % script_name) + "\n", 2)
830 def run_all_tests(self):
831 initTime = datetime.datetime.now()
833 self.run_script('test_setup')
834 self.logger.write("\n", 2, False)
836 self.logger.write(src.printcolors.printcHeader(
837 _("=== STARTING TESTS")) + "\n", 2)
838 self.logger.write("\n", 2, False)
839 self.currentDir = os.path.join(self.sessionDir,
842 self.run_grid_tests()
844 # calculate total execution time
845 totalTime = datetime.datetime.now() - initTime
846 totalTime -= datetime.timedelta(microseconds=totalTime.microseconds)
847 self.logger.write("\n", 2, False)
848 self.logger.write(src.printcolors.printcHeader(_("=== END TESTS")), 2)
849 self.logger.write(" %s\n" % src.printcolors.printcInfo(str(totalTime)),
856 self.run_script('test_cleanup')
857 self.logger.write("\n", 2, False)
860 res_count = "%d / %d" % (self.nb_succeed,
861 self.nb_run - self.nb_acknoledge)
863 res_out = _("Tests Results: %(succeed)d / %(total)d\n") % \
864 { 'succeed': self.nb_succeed, 'total': self.nb_run }
865 if self.nb_succeed == self.nb_run:
866 res_out = src.printcolors.printcSuccess(res_out)
868 res_out = src.printcolors.printcError(res_out)
869 self.logger.write(res_out, 1)
871 if self.nb_timeout > 0:
872 self.logger.write(_("%d tests TIMEOUT\n") % self.nb_timeout, 1)
873 res_count += " TO: %d" % self.nb_timeout
874 if self.nb_not_run > 0:
875 self.logger.write(_("%d tests not executed\n") % self.nb_not_run, 1)
876 res_count += " NR: %d" % self.nb_not_run
878 status = src.OK_STATUS
879 if self.nb_run - self.nb_succeed - self.nb_acknoledge > 0:
880 status = src.KO_STATUS
881 elif self.nb_acknoledge:
882 status = src.KNOWNFAILURE_STATUS
884 self.logger.write(_("Status: %s\n" % status), 3)
886 return self.nb_run - self.nb_succeed - self.nb_acknoledge
889 # Write margin to show test results.
890 def write_test_margin(self, tab):
893 return "| " * (tab - 1) + "+ "