def compose_send_email(exec_type, abs_filepath, logs_dir, results_dir, result, mail_on="per_execution"): """ compose and sends email from smtp server using input arguments as: :Arguments: 1. exec_type - type of test(case/suite/project) 2. abs_filepath - full path of case/suite/project 3. logs_dir - full path of logs directory 4. results_dir - full path of results directory 5. result - execution result 6. mail_on(optional) - it is to specify when to send an email Supported options below: (1) per_execution(default) (2) first_failure (3) every_failure """ resultconverted = {"True": "Pass", "False": "Fail", "ERROR": "Error", "EXCEPTION": "Exception", "RAN": "Ran"}.get(str(result)) subject = str(resultconverted)+": "+file_Utils.getFileName(abs_filepath) body = construct_mail_body(exec_type, abs_filepath, logs_dir, results_dir) report_attachment = results_dir + os.sep + \ file_Utils.getNameOnly(file_Utils.getFileName(abs_filepath)) + ".html" log_attachment = logs_dir + os.sep + \ file_Utils.getNameOnly\ (file_Utils.getFileName(abs_filepath)) + "_consoleLogs.log" if mail_on in ["per_execution"] and file_Utils.fileExists(report_attachment): files = [report_attachment] elif mail_on in ["first_failure", "every_failure"] and file_Utils.fileExists(log_attachment): files = [log_attachment] set_params_send_email(subject, body, files, mail_on)
def print_execution_summary_details(self, suite_tc_exec): """To print the consolidated test cases result in console at the end of Test Case/Test Suite/Project Execution""" for suite_tc in suite_tc_exec: path = suite_tc[3] name = suite_tc[1] if suite_tc_exec[0][0] == 'Suites' and file_Utils.fileExists(path): if suite_tc[0] == 'Testcase': if str(suite_tc[4]).strip().upper() != 'NO_DATA' and \ suite_tc[4] is not False and \ file_Utils.fileExists(suite_tc[4]): name = name + ' [' + os.path.basename( suite_tc[4]) + ']' print_info( ("{0:10}{1:50}{2:10}{3:30}".format(suite_tc[0], name, suite_tc[2], suite_tc[3])))
def warrior_framework_details(): """This gets framework details such the executing framework path, release & version details. """ #The logic uses relative file path to locate Warrior framework and its\ # release notes.Assumes the relative structure remains constant. release = False version = False version_file_path = os.path.normpath(os.path.join(__file__, "..{0}..{0}..".format(os.sep))) version_file = os.path.join(version_file_path, "version.txt") version_file_exists = file_Utils.fileExists(version_file) if version_file_exists: release_notes = open(version_file, "r") for line in release_notes: line = line.strip() #pattern matching Release:<> if re.match('(Release.*):(.*)', line): match = re.match(r'(Release.*):(.*)', line) release = match.group(2) #pattern matching Version:<> if re.match('(Version.*):(.*)', line): match = re.match(r'(Version.*):(.*)', line) version = match.group(2) user = getpass.getuser() if os.getenv("pipmode",None) == "False": #get warriorframework_py3 repo branch proc1 = subprocess.Popen(['git', 'branch'], stdout=subprocess.PIPE) proc2 = subprocess.Popen(['grep', '*'], stdin=proc1.stdout, stdout=subprocess.PIPE, stderr=None) proc1.stdout.close() # Allow proc1 to receive a SIGPIPE if proc2 exits. branch = proc2.communicate()[0] branch = branch.decode('utf-8') branch = branch.strip()[1:] hostname = platform.node() if release and version and version_file_path: pNote("========================== WARRIOR FRAMEWORK DETAILS ==========================", 'notype') print_info('The Warrior framework used is {0}'.format(version_file_path)) print_info('The Warrior framework user is {0}'.format(user)) print_info('The Warrior framework Release is{0}'.format(release)) print_info('The Warrior framework version is{0}'.format(version)) if os.getenv("pipmode",None) == "False": print_info('The Warrior framework branch is{0}'.format(branch)) print_info('The Warrior framework running on python version: {0} with OS: {1}'. format(platform.python_version(), platform.platform())) print_info('Warrior script executed in host [{0}] on [{1}]'.format(hostname, date.today())) pNote("========================== WARRIOR FRAMEWORK DETAILS ==========================", 'notype') #Sleep for the user to view the console for a second on the framework detail time.sleep(2) return None
def get_execution_files(filepath, execution_dir, extn): """Get the execution files like resultfile, logfile etc""" filename = file_Utils.getFileName(filepath) nameonly = file_Utils.getNameOnly(filename) if extn.lower() == "res": fullpath = execution_dir + os.sep + nameonly + "_results" + "." + extn else: fullpath = execution_dir + os.sep + nameonly + '.' + extn if file_Utils.fileExists(fullpath): fullpath = file_Utils.addTimeDate(fullpath) return fullpath
def check_tmp_file_exists(self, system_name="", filename=""): """ check if temp folder exist in the parallel execution result tmp dir """ if system_name != "" and filename == "": filename = data_Utils.getSystemData(self.datafile, system_name, "filename") elif system_name == "" and filename == "": pNote("No system or filename found, needs to provide at least one", "error") path = data_Utils.get_object_from_datarepository( "parallel_exec_tmp_dir") path = os.path.join(path, filename) return file_Utils.fileExists(path)
def check_defect_file(path): """Gets the list of defect json files for the testcase execution """ abs_cur_dir = os.path.abspath(os.curdir) value = None if path.endswith(".json"): defect_file = file_Utils.getAbsPath(path, abs_cur_dir) if file_Utils.fileExists(defect_file): print_info("Defect file location is :{0}".format(defect_file)) value = defect_file else: print_error("File Does not exist in provided location: "\ "{0} relative to cwd".format(path)) return value
def check_get_datafile(self): """Check InputDatFile tag in the xml file and based on the values return the datafile to be used for the testcase/testsuite - If user provided a datafile, will use it. - If user specified 'Default' will use the default datafile - If user did not provide any value will use default datafile - If user specified 'NODATA' will print a msg saying so. """ datafile = xml_Utils.getChildTextbyParentTag(self.filepath, 'Details', 'InputDataFile') if datafile is None or datafile is False or \ str(datafile).strip() == "": if self.filetype == "tc": # print "get default datatype for testcase" datafile = get_default_xml_datafile(self.filepath) if self.filetype == "ts": # Check if test suite datatype starts with iterative. # If yes then get default datafile else set it as false # this is because at testsuite level input datafile is # supported only if the suite datatype is iterative seq/parallel datatype = self.check_get_datatype(False) if str(datatype).lower().startswith("iterative"): datafile = get_default_xml_datafile(self.filepath) else: datafile = False elif self.filetype == "proj": datafile = False elif str(datafile).strip().upper() == "DEFAULT": print_debug( "This testcase will be executed using the default InputDataFile" ) datafile = get_default_xml_datafile(self.filepath) elif str(datafile).strip().upper() == 'NO_DATA': print_debug('This test case will be run without any InputDataFile') datafile = "NO_DATA" elif datafile is not None and datafile is not False: datafile_rel = str(datafile).strip() datafile = file_Utils.getAbsPath(datafile_rel, os.path.dirname(self.filepath)) if str(datafile).strip().upper( ) != 'NO_DATA' and datafile is not False: if not file_Utils.fileExists(datafile): print_debug('\n') print_error("!!! *** InputDataFile does not exist in provided path:" \ "{0} *** !!!".format(datafile)) return datafile
def construct_mail_body(exec_type, abs_filepath, logs_dir, results_dir): """ construct e-mail body with Project, Logs/Results directory & Execution summary :Arguments: 1. exec_type - type of test(case/suite/project) 2. abs_filepath - full path of case/suite/project 3. logs_dir - full path of logs directory 4. results_dir - full path of results directory :Returns: 1. body - return mail body """ junit_result_file = os.path.join( results_dir, file_Utils.getNameOnly(file_Utils.getFileName(abs_filepath))) + "_junit.xml" suite_tc, body = "", "" body_arg = ('<html><body><p><b>{0}</b>{1}</p>' '<p><b>Logs directory:</b>{2}</p>' '<p><b>Results directory:</b>{3}</p>').format(exec_type, abs_filepath,\ logs_dir, results_dir) body_arg1 = ('<p><b>Execution Summary:</b></p>' '<table cellspacing="10" cellpadding="0"><tr><td><b>Type</b>' '</td><td><b>Name</b></td><td><b>Status</b></td>' '<td><b>Path</b></td></tr>') if file_Utils.fileExists(junit_result_file): body_arg = body_arg + body_arg1 junit_object = ExecutionSummary(junit_result_file) project_sum = junit_object.project_summary(junit_result_file) suite_tc_sum = junit_object.suite_summary(junit_result_file) # complete html body that will be sent through mail if exec_type == 'Project: ': project = "" for proj in project_sum: project = project + ('<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>\n'\ .format(proj[0], proj[1], proj[2], proj[3])) for value in suite_tc_sum: suite_tc = suite_tc + ('<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>\n'\ .format(value[0], value[1], value[2], value[3])) body = body_arg + project + suite_tc + "</table></body></html>" elif exec_type == 'Test Suite: ' or exec_type == 'Test Case: ': for value in suite_tc_sum: suite_tc = suite_tc + ('<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>\n'\ .format(value[0], value[1], value[2], value[3])) body = body_arg + suite_tc + "</table></body></html>" else: body = body_arg + "</table></body></html>" return body
def print_result_in_console(self, junit_file): """To print the consolidated test cases result in console at the end of Test Case/Test Suite/Project Execution""" file_type = self.get_file_type(junit_file) # Formatting execution summary as project_summary and suite_summary returns the list values print_info( "+++++++++++++++++++++++++++++++++++++++++++++++++ Execution Summary +++++++++++++++++++++++++++++++++++++++++++++++++" ) print_info("{0:10}{1:50}{2:10}{3:50}".format('Type', 'Name [DataFile]', 'Status', 'Path')) if file_type == "Project": project_exec = self.project_summary(junit_file) invalid_suite_path = [] for proj in project_exec: print_info( ("{0:10}{1:50}{2:10}{3:30}".format(proj[0], proj[1], proj[2], proj[3]))) testsuite_list = common_execution_utils.get_steps_lists( proj[3], "Testsuites", "Testsuite") project_dir = os.path.dirname(proj[3]) for testsuite in testsuite_list: testsuite_rel_path = testsuite_utils.get_path_from_xmlfile( testsuite) if testsuite_rel_path is not None: testsuite_path = Utils.file_Utils.getAbsPath( testsuite_rel_path, project_dir) else: testsuite_path = str(testsuite_rel_path) if not file_Utils.fileExists(testsuite_path): invalid_suite_path.append([ "Suites", os.path.basename(testsuite_path), "ERROR", testsuite_path ]) suite_tc_list = self.suite_summary(junit_file) suite_tc_exec = invalid_suite_path + suite_tc_list self.print_execution_summary_details(suite_tc_exec) elif file_type == "Suites": suite_tc_exec = self.suite_summary(junit_file) self.print_execution_summary_details(suite_tc_exec) print_info( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" )
def _make_ff(self, webdriver_remote_url, desired_capabilites, profile_dir, **kwargs): """Create an instance of firefox browser""" binary = kwargs.get("binary", None) gecko_path = kwargs.get("gecko_path", None) # gecko_log is the absolute path to save geckodriver log gecko_log = kwargs.get("gecko_log", None) proxy_ip = kwargs.get("proxy_ip", None) proxy_port = kwargs.get("proxy_port", None) ff_profile = None # if firefox is being used with proxy, set the profile here # if firefox_proxy details are not given, set profile_dir # as the ff_profile. if proxy_ip is not None and proxy_port is not None: ff_profile = self.set_firefox_proxy(profile_dir, proxy_ip, proxy_port) else: ff_profile = profile_dir log_dir = get_object_from_datarepository("wt_logsdir") if \ gecko_log in [None, False] else gecko_log log_dir = os.path.join( log_dir, "gecko_" + kwargs.get("browser_name", "default") + ".log") browser = None try: if webdriver_remote_url: browser = self._create_remote_web_driver( webdriver.DesiredCapabilities.FIREFOX, webdriver_remote_url, desired_capabilites, ff_profile) else: optional_args = {} ff_capabilities = webdriver.DesiredCapabilities.FIREFOX # This is for internal testing needs...some https cert is not secure # And firefox will need to know how to handle it ff_capabilities['acceptInsecureCerts'] = True if binary not in [False, None]: if not fileExists(binary): print_warning( "Given firefox binary '{}' does not exist, default " "firefox will be used for execution.".format( binary)) binary = None else: print_info("No value given for firefox binary, default " "firefox will be used for execution.") # Force disable marionette, only needs in Selenium 3 with FF ver < 47 # Without these lines, selenium may encounter capability not found issue # https://github.com/seleniumhq/selenium/issues/2739 # https://github.com/SeleniumHQ/selenium/issues/5106#issuecomment-347298110 if self.get_firefox_version(binary) < LooseVersion("47.0.0"): ff_capabilities["marionette"] = False else: # gecko_log will only get generate if there is failure/error # Need to specify log_path for geckodriver log # Gecko driver will only launch if FF version is 47 or above optional_args["log_path"] = log_dir ffbinary = FirefoxBinary( binary) if binary is not None else None if gecko_path is not None: optional_args["executable_path"] = gecko_path browser = webdriver.Firefox(firefox_binary=ffbinary, capabilities=ff_capabilities, firefox_profile=ff_profile, **optional_args) except WebDriverException as err: if "executable needs to be in PATH" in str(err): print_error("Please provide path for geckodriver executable") elif "Expected browser binary location" in str(err): print_error("Please provide path of firefox executable") print_error(err) traceback.print_exc() except Exception as err: print_error(err) traceback.print_exc() if browser is None and\ any((LooseVersion(webdriver.__version__) < LooseVersion("3.5.0"), gecko_path is None)): print_info("Unable to create Firefox browser, one possible reason is because"\ "Firefox version >= 47.0.1 and Selenium version < 3.5"\ "In order to launch Firefox ver 47 and up, Selenium needs to be updated to >= 3.5"\ "and needs geckodriver > 0.16") return browser
def suite_summary(self, junit_file): """ To get the name, status and location of both test suite and test case""" tree = xml_Utils.get_tree_from_file(self.junit_file) suite_tc_list = [] for values in tree.iter('testsuite'): suite_detail = values.attrib suite_name = suite_detail.get('name') suite_status = suite_detail.get('status') suite_location = suite_detail.get('suite_location') suite_result_dir = suite_detail.get('resultsdir') if suite_location is not None: suite_tc_list.append( ["Suites", suite_name, suite_status, suite_location]) testsuite_dir = os.path.dirname(suite_location) testcase_list = common_execution_utils.get_steps_lists( suite_location, "Testcases", "Testcase", randomize=False) for tests in testcase_list: tc_rel_path = testsuite_utils.get_path_from_xmlfile(tests) if tc_rel_path is not None: tc_path = Utils.file_Utils.getAbsPath( tc_rel_path, testsuite_dir) else: tc_path = str(tc_rel_path) if not file_Utils.fileExists(tc_path): suite_tc_list.append([ "Testcase", os.path.basename(tc_path), "ERROR", tc_path ]) #to add Setup results in suite summary for value in tree.iter('Setup'): setup_details = value.attrib setup_status = setup_details.get('status') setup_name = setup_details.get('name') + ".xml" setup_location = setup_details.get('testcasefile_path') case_result_dir_with_tc_name = setup_details.get('resultsdir') if case_result_dir_with_tc_name is not None: case_result_dir = os.path.dirname( case_result_dir_with_tc_name) # suite junit element will not have resultsdir attrib for case execution if suite_result_dir is None or suite_result_dir == case_result_dir: suite_tc_list.append([ "Setup", setup_name, setup_status, setup_location ]) for value in tree.iter('testcase'): testcase_details = value.attrib testcase_status = testcase_details.get('status') testcase_name = testcase_details.get('name') + ".xml" testcase_location = testcase_details.get('testcasefile_path') case_result_dir_with_tc_name = testcase_details.get( 'resultsdir') testcase_datafile = testcase_details.get('data_file') if case_result_dir_with_tc_name is not None: case_result_dir = os.path.dirname( case_result_dir_with_tc_name) # suite junit element will not have resultsdir attrib for case execution if suite_result_dir is None or suite_result_dir == case_result_dir: suite_tc_list.append([ "Testcase", testcase_name, testcase_status, testcase_location, testcase_datafile ]) #to add debug results in suite summary for value in tree.iter('Debug'): debug_details = value.attrib debug_status = debug_details.get('status') debug_name = debug_details.get('name') + ".xml" debug_location = debug_details.get('testcasefile_path') case_result_dir_with_tc_name = debug_details.get('resultsdir') if case_result_dir_with_tc_name is not None: case_result_dir = os.path.dirname( case_result_dir_with_tc_name) # suite junit element will not have resultsdir attrib for case execution if suite_result_dir is None or suite_result_dir == case_result_dir: suite_tc_list.append([ "Debug", debug_name, debug_status, debug_location ]) #to add Cleanup results in suite summary for value in tree.iter('Cleanup'): cleanup_details = value.attrib cleanup_status = cleanup_details.get('status') cleanup_name = cleanup_details.get('name') + ".xml" cleanup_location = cleanup_details.get('testcasefile_path') case_result_dir_with_tc_name = cleanup_details.get( 'resultsdir') if case_result_dir_with_tc_name is not None: case_result_dir = os.path.dirname( case_result_dir_with_tc_name) # suite junit element will not have resultsdir attrib for case execution if suite_result_dir is None or suite_result_dir == case_result_dir: suite_tc_list.append([ "Cleanup", cleanup_name, cleanup_status, cleanup_location ]) # suite_tc_list appends suites and test cases as per execution order return suite_tc_list
def set_line_objs(self): """ call to create a new obj per item""" self.lineCount = 0 project_node_list = [self.junit_root] for project_node in project_node_list: self.create_line_result(project_node, "Project") for pro_node in project_node.findall("property"): if pro_node.get('name') == 'location': pro_location = pro_node.get('value') testsuite_list = common_execution_utils.get_steps_lists( pro_location, "Testsuites", "Testsuite") project_dir = os.path.dirname(pro_location) for testsuite in testsuite_list: testsuite_rel_path = testsuite_utils.get_path_from_xmlfile( testsuite) if testsuite_rel_path is not None: testsuite_path = Utils.file_Utils.getAbsPath( testsuite_rel_path, project_dir) else: testsuite_path = str(testsuite_rel_path) if not file_Utils.fileExists(testsuite_path): self.create_line_result( { 'name': os.path.splitext( os.path.basename(testsuite_path))[0], 'status': 'ERROR' }, "InvalidTestsuite") for testsuite_node in project_node.findall("testsuite"): self.create_line_result(testsuite_node, "Testsuite") all_testcases = [] if testsuite_node.get('suite_location'): testsuite_dir = os.path.dirname( testsuite_node.get('suite_location')) testcase_list = common_execution_utils.get_steps_lists( testsuite_node.get('suite_location'), "Testcases", "Testcase", randomize=False) for tests in testcase_list: tc_rel_path = testsuite_utils.get_path_from_xmlfile( tests) if tc_rel_path is not None: tc_path = Utils.file_Utils.getAbsPath( tc_rel_path, testsuite_dir) else: tc_path = str(tc_rel_path) if not file_Utils.fileExists(tc_path): all_testcases.append({ 'name': os.path.splitext(os.path.basename(tc_path))[0], 'status': 'ERROR' }) full_testcasess = all_testcases + testsuite_node.findall( "testcase") #to add setup result in html file for setup_node in testsuite_node.findall("Setup"): self.create_line_result(setup_node, "Setup") self.steps = 0 for step_node in setup_node.findall("properties"): for node in step_node.findall("property"): if node.get('type') == 'keyword': self.steps += 1 self.create_line_result(node, "Keyword") for testcase_node in full_testcasess: self.create_line_result(testcase_node, "Testcase") self.steps = 0 if testcase_node.get('status') != 'ERROR': for step_node in testcase_node.findall("properties"): for node in step_node.findall("property"): if node.get('type') == 'keyword': self.steps += 1 self.create_line_result(node, "Keyword") #to add debug result in html file for debug_node in testsuite_node.findall("Debug"): self.create_line_result(debug_node, "Debug") self.steps = 0 for step_node in debug_node.findall("properties"): for node in step_node.findall("property"): if node.get('type') == 'keyword': self.steps += 1 self.create_line_result(node, "Keyword") #to add cleanup result in html file for cleanup_node in testsuite_node.findall("Cleanup"): self.create_line_result(cleanup_node, "Cleanup") self.steps = 0 for step_node in cleanup_node.findall("properties"): for node in step_node.findall("property"): if node.get('type') == 'keyword': self.steps += 1 self.create_line_result(node, "Keyword")