X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=commands%2Ftest.py;h=9baf117d2243642a22d2a8c06231db8d05ffb441;hb=86042d1d4bc886479259b14865ad220f1a8c8a1a;hp=d16e9df60f9723b3f95003c161f949dd61d331e6;hpb=39f16786c8fb446a49f6040adabe30298cae5bc9;p=tools%2Fsat.git diff --git a/commands/test.py b/commands/test.py index d16e9df..9baf117 100644 --- a/commands/test.py +++ b/commands/test.py @@ -34,26 +34,22 @@ from src.xmlManager import add_simple_node # Define all possible option for the test command : sat test parser = src.options.Options() -parser.add_option('a', 'appli', 'string', 'appli', - _('Use this option to specify the path to an installed application.')) -parser.add_option('g', 'grid', 'string', 'grid', - _("""Indicate the name of the grid to test. -\tThis name has to be registered in sat. If your test base is not known by sat, use the option --dir.""")) -parser.add_option('m', 'module', 'list', 'modules', - _('Indicate which module(s) to test (subdirectory of the grid).')) -parser.add_option('t', 'type', 'list', 'types', - _('Indicate which type(s) to test (subdirectory of the module).')) -parser.add_option('d', 'dir', 'string', 'dir', - _('Indicate the directory containing the test base.'), "") -parser.add_option('', 'mode', 'string', 'mode', - _("Indicate which kind of test to run. If MODE is 'batch' only python and NO_GUI tests are run."), "normal") +parser.add_option('b', 'base', 'string', 'base', + _("Optional: Indicate the name of the test base to use.\n\tThis name has to" + " be registered in your application and in a project.\n\tA path to a " + "test base can also be used.")) +parser.add_option('l', 'launcher', 'string', 'launcher', + _("Optional: Use this option to specify the path to a SALOME launcher to " + "use to launch the test scripts of the test base.")) +parser.add_option('g', 'grid', 'list', 'grids', + _('Optional: Indicate which grid(s) to test (subdirectory of the test ' + 'base).')) +parser.add_option('s', 'session', 'list', 'sessions', + _('Optional: indicate which session(s) to test (subdirectory of the ' + 'grid).')) parser.add_option('', 'display', 'string', 'display', - _("""Set the display where to launch SALOME. -\tIf value is NO then option --show-desktop=0 will be used to launch SALOME.""")) -parser.add_option('n', 'name', 'string', 'session', - _('Give a name to the test session (REQUIRED if no product).')) -parser.add_option('', 'light', 'boolean', 'light', - _('Only run minimal tests declared in TestsLight.txt.'), False) + _("Optional: set the display where to launch SALOME.\n" +"\tIf value is NO then option --show-desktop=0 will be used to launch SALOME.")) def description(): '''method that is called when salomeTools is called with --help option. @@ -61,26 +57,37 @@ def description(): :return: The text to display for the test command description. :rtype: str ''' - return _("The test command runs a test base on a SALOME installation.") + return _("The test command runs a test base on a SALOME installation.\n\n" + "example:\nsat test SALOME-master --grid GEOM --session light") def parse_option(args, config): + """ Parse the options and do some verifications about it + + :param args List: The list of arguments of the command + :param config Config: The global configuration + :return: the options of the current command launch and the full arguments + :rtype: Tuple (options, args) + """ (options, args) = parser.parse_args(args) - if not options.appli: - options.appli = "" - elif not os.path.isabs(options.appli): + if not options.launcher: + options.launcher = "" + elif not os.path.isabs(options.launcher): if not src.config_has_application(config): raise src.SatException(_("An application is required to use a " "relative path with option --appli")) - options.appli = os.path.join(config.APPLICATION.workdir, options.appli) + options.launcher = os.path.join(config.APPLICATION.workdir, + options.launcher) - if not os.path.exists(options.appli): - raise src.SatException(_("Application not found: %s") % - options.appli) + if not os.path.exists(options.launcher): + raise src.SatException(_("Launcher not found: %s") % + options.launcher) return (options, args) def ask_a_path(): + """ + """ path = raw_input("enter a path where to save the result: ") if path == "": result = raw_input("the result will be not save. Are you sure to " @@ -145,55 +152,55 @@ def move_test_results(in_dir, what, out_dir, logger): shutil.copy2(os.path.join(in_dir, what, 'env_info.py'), os.path.join(finalPath, what, 'env_info.py')) - # for all sub directory (ie grid) in the BASES directory - for grid in os.listdir(os.path.join(in_dir, what, 'BASES')): - outgrid = os.path.join(finalPath, what, 'BASES', grid) - ingrid = os.path.join(in_dir, what, 'BASES', grid) + # for all sub directory (ie testbase) in the BASES directory + for testbase in os.listdir(os.path.join(in_dir, what, 'BASES')): + outtestbase = os.path.join(finalPath, what, 'BASES', testbase) + intestbase = os.path.join(in_dir, what, 'BASES', testbase) # ignore files in root dir - if not os.path.isdir(ingrid): + if not os.path.isdir(intestbase): continue - os.makedirs(outgrid) - #logger.write(" copy grid %s\n" % grid, 5) + os.makedirs(outtestbase) + #logger.write(" copy testbase %s\n" % testbase, 5) - for module_ in [m for m in os.listdir(ingrid) if os.path.isdir( - os.path.join(ingrid, m))]: + for grid_ in [m for m in os.listdir(intestbase) if os.path.isdir( + os.path.join(intestbase, m))]: # ignore source configuration directories - if module_[:4] == '.git' or module_ == 'CVS': + if grid_[:4] == '.git' or grid_ == 'CVS': continue - outmodule = os.path.join(outgrid, module_) - inmodule = os.path.join(ingrid, module_) - os.makedirs(outmodule) - #logger.write(" copy module %s\n" % module_, 5) + outgrid = os.path.join(outtestbase, grid_) + ingrid = os.path.join(intestbase, grid_) + os.makedirs(outgrid) + #logger.write(" copy grid %s\n" % grid_, 5) - if module_ == 'RESSOURCES': - for file_name in os.listdir(inmodule): - if not os.path.isfile(os.path.join(inmodule, + if grid_ == 'RESSOURCES': + for file_name in os.listdir(ingrid): + if not os.path.isfile(os.path.join(ingrid, file_name)): continue - f = open(os.path.join(outmodule, file_name), "w") - f.write(save_file(os.path.join(inmodule, file_name), + f = open(os.path.join(outgrid, file_name), "w") + f.write(save_file(os.path.join(ingrid, file_name), finalPath)) f.close() else: - for type_name in [t for t in os.listdir(inmodule) if - os.path.isdir(os.path.join(inmodule, t))]: - outtype = os.path.join(outmodule, type_name) - intype = os.path.join(inmodule, type_name) - os.makedirs(outtype) + for session_name in [t for t in os.listdir(ingrid) if + os.path.isdir(os.path.join(ingrid, t))]: + outsession = os.path.join(outgrid, session_name) + insession = os.path.join(ingrid, session_name) + os.makedirs(outsession) - for file_name in os.listdir(intype): - if not os.path.isfile(os.path.join(intype, + for file_name in os.listdir(insession): + if not os.path.isfile(os.path.join(insession, file_name)): continue if file_name.endswith('result.py'): - shutil.copy2(os.path.join(intype, file_name), - os.path.join(outtype, file_name)) + shutil.copy2(os.path.join(insession, file_name), + os.path.join(outsession, file_name)) else: - f = open(os.path.join(outtype, file_name), "w") - f.write(save_file(os.path.join(intype, + f = open(os.path.join(outsession, file_name), "w") + f.write(save_file(os.path.join(insession, file_name), finalPath)) f.close() @@ -214,31 +221,11 @@ def check_remote_machine(machine_name, logger): if p.returncode != 0: logger.write(src.printcolors.printc(src.KO_STATUS) + "\n", 1) logger.write(" " + src.printcolors.printcError(p.stderr.read()), 2) - raise src.SatException("No ssh access to the display machine.") + logger.write(src.printcolors.printcWarning(( + "No ssh access to the display machine.")),1) else: logger.write(src.printcolors.printcSuccess(src.OK_STATUS) + "\n\n", 4) -## -# Transform YYYYMMDD_hhmmss into YYYY-MM-DD hh:mm:ss. -def parse_date(date): - if len(date) != 15: - return date - res = "%s-%s-%s %s:%s:%s" % (date[0:4], date[4:6], date[6:8], date[9:11], date[11:13], date[13:]) - return res - -## -# Writes a report file from a XML tree. -def write_report(filename, xmlroot, stylesheet): - if not os.path.exists(os.path.dirname(filename)): - os.makedirs(os.path.dirname(filename)) - - f = open(filename, "w") - f.write("\n") - if len(stylesheet) > 0: - f.write("\n" % stylesheet) - f.write(etree.tostring(xmlroot, encoding='utf-8')) - f.close() - ## # Creates the XML report for a product. def create_test_report(config, dest_path, stylesheet, xmlname=""): @@ -251,18 +238,24 @@ def create_test_report(config, dest_path, stylesheet, xmlname=""): if withappli: - add_simple_node(prod_node, "version_to_download", config.APPLICATION.name) + add_simple_node(prod_node, "version_to_download", + config.APPLICATION.name) add_simple_node(prod_node, "out_dir", config.APPLICATION.workdir) # add environment exec_node = add_simple_node(prod_node, "exec") exec_node.append(etree.Element("env", name="Host", value=config.VARS.node)) - exec_node.append(etree.Element("env", name="Architecture", value=config.VARS.dist)) - exec_node.append(etree.Element("env", name="Number of processors", value=str(config.VARS.nb_proc))) - exec_node.append(etree.Element("env", name="Begin date", value=parse_date(config.VARS.datehour))) - exec_node.append(etree.Element("env", name="Command", value=config.VARS.command)) - exec_node.append(etree.Element("env", name="sat version", value=config.INTERNAL.sat_version)) + exec_node.append(etree.Element("env", name="Architecture", + value=config.VARS.dist)) + exec_node.append(etree.Element("env", name="Number of processors", + value=str(config.VARS.nb_proc))) + exec_node.append(etree.Element("env", name="Begin date", + value=src.parse_date(config.VARS.datehour))) + exec_node.append(etree.Element("env", name="Command", + value=config.VARS.command)) + exec_node.append(etree.Element("env", name="sat version", + value=config.INTERNAL.sat_version)) if 'TESTS' in config: tests = add_simple_node(prod_node, "tests") @@ -271,48 +264,60 @@ def create_test_report(config, dest_path, stylesheet, xmlname=""): amend = add_simple_node(prod_node, "amend") tt = {} for test in config.TESTS: - if not tt.has_key(test.grid): - tt[test.grid] = [test] + if not tt.has_key(test.testbase): + tt[test.testbase] = [test] else: - tt[test.grid].append(test) + tt[test.testbase].append(test) - for grid in tt.keys(): - gn = add_simple_node(tests, "grid") - gn.attrib['name'] = grid + for testbase in tt.keys(): + gn = add_simple_node(tests, "testbase") + gn.attrib['name'] = testbase nb, nb_pass, nb_failed, nb_timeout, nb_not_run = 0, 0, 0, 0, 0 - modules = {} - types = {} - for test in tt[grid]: - #print test.module - if not modules.has_key(test.module): - mn = add_simple_node(gn, "module") - mn.attrib['name'] = test.module - modules[test.module] = mn - - if not types.has_key("%s/%s" % (test.module, test.type)): - tyn = add_simple_node(mn, "type") - tyn.attrib['name'] = test.type - types["%s/%s" % (test.module, test.type)] = tyn + grids = {} + sessions = {} + for test in tt[testbase]: + #print test.grid + if not grids.has_key(test.grid): + mn = add_simple_node(gn, "grid") + mn.attrib['name'] = test.grid + grids[test.grid] = mn + + if not sessions.has_key("%s/%s" % (test.grid, test.session)): + tyn = add_simple_node(mn, "session") + tyn.attrib['name'] = test.session + sessions["%s/%s" % (test.grid, test.session)] = tyn for script in test.script: - tn = add_simple_node(types["%s/%s" % (test.module, test.type)], "test") - #tn.attrib['grid'] = test.grid - #tn.attrib['module'] = test.module - tn.attrib['type'] = test.type + tn = add_simple_node(sessions[ + "%s/%s" % (test.grid, test.session)], "test") + tn.attrib['session'] = test.session tn.attrib['script'] = script.name if 'callback' in script: try: cnode = add_simple_node(tn, "callback") if src.architecture.is_windows(): import string - cnode.text = filter(lambda x: x in string.printable, - script.callback) + cnode.text = filter( + lambda x: x in string.printable, + script.callback) else: - cnode.text = script.callback.decode('string_escape') + cnode.text = script.callback.decode( + 'string_escape') except UnicodeDecodeError as exc: - zz = script.callback[:exc.start] + '?' + script.callback[exc.end-2:] + zz = (script.callback[:exc.start] + + '?' + + script.callback[exc.end-2:]) cnode = add_simple_node(tn, "callback") cnode.text = zz.decode("UTF-8") + + # Add the script content + cnode = add_simple_node(tn, "content") + cnode.text = script.content + + # Add the script execution log + cnode = add_simple_node(tn, "out") + cnode.text = script.out + if 'amend' in script: cnode = add_simple_node(tn, "amend") cnode.text = script.amend.decode("UTF-8") @@ -325,8 +330,11 @@ def create_test_report(config, dest_path, stylesheet, xmlname=""): if "amend" in script: amend_test = add_simple_node(amend, "atest") - amend_test.attrib['name'] = os.path.join(test.module, test.type, script.name) - amend_test.attrib['reason'] = script.amend.decode("UTF-8") + amend_test.attrib['name'] = os.path.join(test.grid, + test.session, + script.name) + amend_test.attrib['reason'] = script.amend.decode( + "UTF-8") # calculate status nb += 1 @@ -337,21 +345,29 @@ def create_test_report(config, dest_path, stylesheet, xmlname=""): if "known_error" in script: kf_script = add_simple_node(known_errors, "error") - kf_script.attrib['name'] = os.path.join(test.module, test.type, script.name) + kf_script.attrib['name'] = os.path.join(test.grid, + test.session, + script.name) kf_script.attrib['date'] = script.known_error.date - kf_script.attrib['expected'] = script.known_error.expected - kf_script.attrib['comment'] = script.known_error.comment.decode("UTF-8") - kf_script.attrib['fixed'] = str(script.known_error.fixed) - overdue = datetime.datetime.today().strftime("%Y-%m-%d") > script.known_error.expected + kf_script.attrib[ + 'expected'] = script.known_error.expected + kf_script.attrib[ + 'comment'] = script.known_error.comment.decode("UTF-8") + kf_script.attrib['fixed'] = str( + script.known_error.fixed) + overdue = datetime.datetime.today().strftime("%Y-%m-" + "%d") > script.known_error.expected if overdue: kf_script.attrib['overdue'] = str(overdue) elif script.res == src.KO_STATUS: new_err = add_simple_node(new_errors, "new_error") - script_path = os.path.join(test.module, test.type, script.name) + script_path = os.path.join(test.grid, + test.session, script.name) new_err.attrib['name'] = script_path - new_err.attrib['cmd'] = "sat testerror %s -s %s -c 'my comment' -p %s" % \ - (application_name, script_path, config.VARS.dist) + new_err.attrib['cmd'] = ("sat testerror %s -s %s -c 'my" + " comment' -p %s" % \ + (application_name, script_path, config.VARS.dist)) gn.attrib['total'] = str(nb) @@ -365,7 +381,9 @@ def create_test_report(config, dest_path, stylesheet, xmlname=""): if not xmlname.endswith(".xml"): xmlname += ".xml" - write_report(os.path.join(dest_path, xmlname), root, stylesheet) + src.xmlManager.write_report(os.path.join(dest_path, xmlname), + root, + stylesheet) return src.OK_STATUS def run(args, runner, logger): @@ -373,44 +391,32 @@ def run(args, runner, logger): ''' (options, args) = parse_option(args, runner.cfg) - if options.grid and options.dir: - raise src.SatException(_("The options --grid and --dir are not " - "compatible!")) - - with_product = False + with_application = False if runner.cfg.VARS.application != 'None': logger.write(_('Running tests on application %s\n') % src.printcolors.printcLabel( runner.cfg.VARS.application), 1) - with_product = True - elif options.dir: - logger.write(_('Running tests from directory %s\n') % - src.printcolors.printcLabel(options.dir), 1) - elif not options.grid: - raise src.SatException(_('a grid or a directory is required')) - - if with_product: + with_application = True + elif not options.base: + raise src.SatException(_('A test base is required. Use the --base ' + 'option')) + + if with_application: # check if environment is loaded if 'KERNEL_ROOT_DIR' in os.environ: logger.write(src.printcolors.printcWarning(_("WARNING: " "SALOME environment already sourced")) + "\n", 1) - elif options.appli: + elif options.launcher: logger.write(src.printcolors.printcWarning(_("Running SALOME " "application.")) + "\n\n", 1) else: - logger.write(src.printcolors.printcWarning(_("WARNING running " - "without a product.")) + "\n\n", 1) - - # name for session is required - if not options.session: - raise src.SatException(_("--name argument is required when no " - "product is specified.")) - - # check if environment is loaded - if not 'KERNEL_ROOT_DIR' in os.environ: - raise src.SatException(_("SALOME environment not found") + "\n") + msg = _("Impossible to find any launcher.\nPlease specify an " + "application or a launcher") + logger.write(src.printcolors.printcError(msg)) + logger.write("\n") + return 1 # set the display show_desktop = (options.display and options.display.upper() == "NO") @@ -422,7 +428,8 @@ def run(args, runner, logger): os.environ['DISPLAY'] = options.display elif 'DISPLAY' not in os.environ: # if no display set - if 'display' in runner.cfg.SITE.test and len(runner.cfg.SITE.test.display) > 0: + if ('display' in runner.cfg.SITE.test and + len(runner.cfg.SITE.test.display) > 0): # use default value for test tool os.environ['DISPLAY'] = runner.cfg.SITE.test.display else: @@ -430,8 +437,8 @@ def run(args, runner, logger): # initialization ################# - if with_product: - tmp_dir = runner.cfg.SITE.test.tmp_dir_with_product + if with_application: + tmp_dir = runner.cfg.SITE.test.tmp_dir_with_application else: tmp_dir = runner.cfg.SITE.test.tmp_dir @@ -460,21 +467,21 @@ def run(args, runner, logger): content = "\n".join(lines) - # create hash from session information - dirname = sha1(content).hexdigest() - session_dir = os.path.join(tmp_dir, dirname) - os.makedirs(session_dir) - os.environ['TT_TMP_RESULT'] = session_dir + # create hash from context information + dirname = sha1(content.encode()).hexdigest() + base_dir = os.path.join(tmp_dir, dirname) + os.makedirs(base_dir) + os.environ['TT_TMP_RESULT'] = base_dir # create env_info file - f = open(os.path.join(session_dir, 'env_info.py'), "w") + f = open(os.path.join(base_dir, 'env_info.py'), "w") f.write(content) f.close() # create working dir and bases dir - working_dir = os.path.join(session_dir, 'WORK') + working_dir = os.path.join(base_dir, 'WORK') os.makedirs(working_dir) - os.makedirs(os.path.join(session_dir, 'BASES')) + os.makedirs(os.path.join(base_dir, 'BASES')) os.chdir(working_dir) if 'PYTHONPATH' not in os.environ: @@ -486,47 +493,47 @@ def run(args, runner, logger): # launch of the tests ##################### - grid = "" - if options.grid: - grid = options.grid - elif not options.dir and with_product and "test_base" in runner.cfg.APPLICATION: - grid = runner.cfg.APPLICATION.test_base.name + test_base = "" + if options.base: + test_base = options.base + elif with_application and "test_base" in runner.cfg.APPLICATION: + test_base = runner.cfg.APPLICATION.test_base.name src.printcolors.print_value(logger, _('Display'), os.environ['DISPLAY'], 2) src.printcolors.print_value(logger, _('Timeout'), runner.cfg.SITE.test.timeout, 2) - if 'timeout_app' in runner.cfg.SITE.test: - src.printcolors.print_value(logger, _('Timeout Salome'), - runner.cfg.SITE.test.timeout_app, 2) - src.printcolors.print_value(logger, _('Light mode'), options.light, 2) - src.printcolors.print_value(logger, _("Working dir"), session_dir, 3) + src.printcolors.print_value(logger, _("Working dir"), base_dir, 3) # create the test object test_runner = src.test_module.Test(runner.cfg, logger, - session_dir, - grid=grid, - modules=options.modules, - types=options.types, - appli=options.appli, - mode=options.mode, - dir_=options.dir, - show_desktop=show_desktop, - light=options.light) + base_dir, + testbase=test_base, + grids=options.grids, + sessions=options.sessions, + launcher=options.launcher, + show_desktop=show_desktop) + if not test_runner.test_base_found: + # Fail + return 1 + # run the test logger.allowPrintLevel = False - retcode = test_runner.run_all_tests(options.session) + retcode = test_runner.run_all_tests() logger.allowPrintLevel = True logger.write(_("Tests finished"), 1) logger.write("\n", 2, False) logger.write(_("\nGenerate the specific test log\n"), 5) - out_dir = os.path.join(runner.cfg.SITE.log.log_dir, "TEST") + out_dir = os.path.join(runner.cfg.USER.log_dir, "TEST") src.ensure_path_exists(out_dir) name_xml_board = logger.logFileName.split(".")[0] + "board" + ".xml" - create_test_report(runner.cfg, out_dir, "test.xsl", xmlname = name_xml_board) + create_test_report(runner.cfg, + out_dir, + "test.xsl", + xmlname = name_xml_board) xml_board_path = os.path.join(out_dir, name_xml_board) logger.l_logFiles.append(xml_board_path) logger.add_link(os.path.join("TEST", name_xml_board), @@ -534,5 +541,10 @@ def run(args, runner, logger): retcode, "Click on the link to get the detailed test results") + logger.write(_("Removing the temporary directory: " + "rm -rf %s\n" % test_runner.tmp_working_dir), 5) + if os.path.exists(test_runner.tmp_working_dir): + shutil.rmtree(test_runner.tmp_working_dir) + return retcode