def _artifactor_skip_providers(request, providers, skip_msg): skip_data = { 'type': 'provider', 'reason': ', '.join(p.key for p in providers), } fire_art_test_hook(request.node, 'skip_test', skip_data=skip_data) pytest.skip(skip_msg)
def add_log(self, log_name): """ Adds a log file to the merkyl process. This function adds a log file path to the merkyl process on the appliance. This is relevant only for the duration of the test. At the end of the test, the file is removed from the merkyl tracker. Note that this is a blocking call, ie, we ensure that the file is being logged by merkyl, before we continue. This is important and prevents the file_add operation being queued and processes which generate log information activating before the log is being monitored. This is achieved using the grab_result switch, but in fact, nothing will be received. It is worth noting that the file path must be "discoverable" by merkyl. This may mean editing the allowed_files prior to deploying merkyl. Args: log_name: Full path to the log file wishing to be monitored. """ fire_art_test_hook(self.node, 'add_log_merkyl', ip=self.ip, filename=log_name, grab_result=True)
def _take_screenshot(name): logger.info("Taking a screenshot named {}".format(name)) ss, ss_error = take_browser_screenshot() g_id = fauxfactory.gen_alpha(length=6) if ss: fire_art_test_hook(item, 'filedump', description="Screenshot {}".format(name), file_type="screenshot", mode="wb", contents_base64=True, contents=ss, display_glyph="camera", group_id="fix-screenshot-{}".format(g_id), slaveid=store.slaveid) if ss_error: fire_art_test_hook(item, 'filedump', description="Screenshot error {}".format(name), mode="w", contents_base64=False, contents=ss_error, display_type="danger", group_id="fix-screenshot-{}".format(g_id), slaveid=store.slaveid)
def resolve_blockers(item, blockers): if not isinstance(blockers, (list, tuple, set)): raise ValueError("Type of the 'blockers' parameter must be one of: list, tuple, set") # Prepare the global env for the kwarg insertion appliance = find_appliance(item) global_env = dict( appliance_version=appliance.version, appliance_downstream=appliance.is_downstream, item=item, blockers=blockers, ) # We will now extend the env with fixtures, so they can be used in the guard functions # We will however add only those that are not in the global_env otherwise we could overwrite # our own stuff. params = extract_fixtures_values(item) for funcarg, value in params.items(): if funcarg not in global_env: global_env[funcarg] = value # Check blockers use_blockers = [] # Bugzilla shortcut blockers = map(lambda b: "BZ#{}".format(b) if isinstance(b, int) else b, blockers) for blocker in map(Blocker.parse, blockers): if blocker.blocks: use_blockers.append(blocker) # Unblocking discard_blockers = set([]) for blocker in use_blockers: unblock_func = kwargify(blocker.kwargs.get("unblock")) local_env = {"blocker": blocker} local_env.update(global_env) if unblock_func(**local_env): discard_blockers.add(blocker) for blocker in discard_blockers: use_blockers.remove(blocker) # We now have those that block testing, so we have to skip # Let's go in the order that they were added # Custom actions first for blocker in use_blockers: if "custom_action" in blocker.kwargs: action = kwargify(blocker.kwargs["custom_action"]) local_env = {"blocker": blocker} local_env.update(global_env) action(**local_env) # And then skip if use_blockers: bugs = [bug.bug_id for bug in use_blockers if hasattr(bug, "bug_id")] skip_data = {'type': 'blocker', 'reason': bugs} fire_art_test_hook(item, 'skip_test', skip_data=skip_data) pytest.skip("Skipping due to these blockers:\n{}".format( "\n".join( "- {}".format(str(blocker)) for blocker in use_blockers ) ))
def reset_log(self, log_name): """ Resets log This function clears content of a log file that merkyl is tailing. Note that file stays open and merkyl keeps tailing it. Args: log_name: Full path to the log file that you want to reset """ fire_art_test_hook( self.node, 'reset_log_merkyl', ip=self.ip, filename=log_name, grab_result=True)
def save_screenshot(node, ss, sse): if ss: fire_art_test_hook( node, 'filedump', description="RBAC Screenshot", file_type="rbac_screenshot", mode="wb", contents_base64=True, contents=ss, display_glyph="camera", group_id="RBAC", slaveid=store.slaveid) if sse: fire_art_test_hook( node, 'filedump', description="RBAC Screenshot error", file_type="rbac_screenshot_error", mode="w", contents_base64=False, contents=sse, display_type="danger", group_id="RBAC", slaveid=store.slaveid)
def save_traceback_file(node, contents): """A convenience function for artifactor file sending This function simply takes the nodes id and the contents of the file and processes them and sends them to artifactor Args: node: A pytest node contents: The contents of the traceback file """ fire_art_test_hook( node, 'filedump', description="RBAC Traceback", contents=contents, file_type="rbac", group_id="RBAC", slaveid=store.slaveid)
def _take_screenshot(name): logger.info("Taking a screenshot named {}".format(name)) ss, ss_error = take_browser_screenshot() g_id = fauxfactory.gen_alpha(length=6) if ss: fire_art_test_hook( item, 'filedump', description="Screenshot {}".format(name), file_type="screenshot", mode="wb", contents_base64=True, contents=ss, display_glyph="camera", group_id="fix-screenshot-{}".format(g_id), slaveid=store.slaveid) if ss_error: fire_art_test_hook( item, 'filedump', description="Screenshot error {}".format(name), mode="w", contents_base64=False, contents=ss_error, display_type="danger", group_id="fix-screenshot-{}".format(g_id), slaveid=store.slaveid)
def save_traceback_file(node, contents): """A convenience function for artifactor file sending This function simply takes the nodes id and the contents of the file and processes them and sends them to artifactor Args: node: A pytest node contents: The contents of the traceback file """ fire_art_test_hook(node, 'filedump', description="RBAC Traceback", contents=contents, file_type="rbac", group_id="RBAC", slaveid=store.slaveid)
def handle_assert_artifacts(request, fail_message=None): appliance = find_appliance(request) if isinstance(appliance, DummyAppliance): return if not fail_message: short_tb = '{}'.format(sys.exc_info()[1]) short_tb = base64_from_text(short_tb) var_tb = traceback.format_tb(sys.exc_info()[2]) full_tb = "".join(var_tb) full_tb = base64_from_text(full_tb) else: short_tb = full_tb = base64_from_text(fail_message) try: ss = cfme.utils.browser.browser().get_screenshot_as_base64() ss_error = None except Exception as b_ex: ss = None if str(b_ex): ss_error = '{}: {}'.format(type(b_ex).__name__, str(b_ex)) else: ss_error = type(b_ex).__name__ if ss_error: ss_error = base64_from_text(ss_error) # A simple id to match the artifacts together sa_id = "softassert-{}".format(fauxfactory.gen_alpha(length=3).upper()) from cfme.fixtures.pytest_store import store node = request.node fire_art_test_hook( node, 'filedump', description="Soft Assert Traceback", contents=full_tb, file_type="soft_traceback", display_type="danger", display_glyph="align-justify", contents_base64=True, group_id=sa_id, slaveid=store.slaveid) fire_art_test_hook( node, 'filedump', description="Soft Assert Short Traceback", contents=short_tb, file_type="soft_short_tb", display_type="danger", display_glyph="align-justify", contents_base64=True, group_id=sa_id, slaveid=store.slaveid) if ss is not None: fire_art_test_hook( node, 'filedump', description="Soft Assert Exception screenshot", file_type="screenshot", mode="wb", contents_base64=True, contents=ss, display_glyph="camera", group_id=sa_id, slaveid=store.slaveid) if ss_error is not None: fire_art_test_hook( node, 'filedump', description="Soft Assert Screenshot error", mode="w", contents_base64=True, contents=ss_error, display_type="danger", group_id=sa_id, slaveid=store.slaveid)
def handle_assert_artifacts(request, fail_message=None): appliance = find_appliance(request) if isinstance(appliance, DummyAppliance): return if not fail_message: short_tb = '{}'.format(sys.exc_info()[1]) short_tb = short_tb.encode('base64') var_tb = traceback.format_tb(sys.exc_info()[2]) full_tb = "".join(var_tb) full_tb = full_tb.encode('base64') else: short_tb = full_tb = fail_message.encode('base64') try: ss = cfme.utils.browser.browser().get_screenshot_as_base64() ss_error = None except Exception as b_ex: ss = None if str(b_ex): ss_error = '{}: {}'.format(type(b_ex).__name__, str(b_ex)) else: ss_error = type(b_ex).__name__ if ss_error: ss_error = ss_error.encode('base64') # A simple id to match the artifacts together sa_id = "softassert-{}".format(fauxfactory.gen_alpha(length=3).upper()) from cfme.fixtures.pytest_store import store node = request.node fire_art_test_hook( node, 'filedump', description="Soft Assert Traceback", contents=full_tb, file_type="soft_traceback", display_type="danger", display_glyph="align-justify", contents_base64=True, group_id=sa_id, slaveid=store.slaveid) fire_art_test_hook( node, 'filedump', description="Soft Assert Short Traceback", contents=short_tb, file_type="soft_short_tb", display_type="danger", display_glyph="align-justify", contents_base64=True, group_id=sa_id, slaveid=store.slaveid) if ss is not None: fire_art_test_hook( node, 'filedump', description="Soft Assert Exception screenshot", file_type="screenshot", mode="wb", contents_base64=True, contents=ss, display_glyph="camera", group_id=sa_id, slaveid=store.slaveid) if ss_error is not None: fire_art_test_hook( node, 'filedump', description="Soft Assert Screenshot error", mode="w", contents_base64=True, contents=ss_error, display_type="danger", group_id=sa_id, slaveid=store.slaveid)
def pytest_runtest_teardown(item, nextitem): qa_string = "Unknown,None" if hasattr(item, "_metadata") and item._metadata.get('owner') is not None: # The owner is specified in metadata qa_string = "{},from metadata" else: try: qa_arr = [] results = dig_code(item) for idx in range(min(2, len(results))): qa_arr.append("{},{:.2f}%\n".format(results[idx][0], results[idx][1])) if qa_arr: qa_string = "".join(qa_arr) except: pass fire_art_test_hook( item, 'filedump', description="QA Contact", contents=str(qa_string), file_type="qa_contact", group_id="qa-contact", slaveid=store.slaveid)
def pytest_runtest_call(item): try: yield finally: if "smtp_test" not in (item.funcargs or []): return try: fire_art_test_hook( item, "filedump", description="received e-mails", contents=item.funcargs["smtp_test"].get_html_report(), file_type="html", display_glyph="align-justify", group_id="misc-artifacts", ) except Exception as e: logger.exception(e) logger.error("Something happened to the SMTP collector.")
def get_log(self, log_name): """ A simple getter for log files. Returns the cached content of a particular log Args: log_name: Full path to the log file wishing to be received. """ res = fire_art_test_hook( self.node, 'get_log_merkyl', ip=self.ip, filename=log_name, grab_result=True) return res['merkyl_content']
def save_screenshot(node, ss, sse): if ss: fire_art_test_hook(node, 'filedump', description="RBAC Screenshot", file_type="rbac_screenshot", mode="wb", contents_base64=True, contents=ss, display_glyph="camera", group_id="RBAC", slaveid=store.slaveid) if sse: fire_art_test_hook(node, 'filedump', description="RBAC Screenshot error", file_type="rbac_screenshot_error", mode="w", contents_base64=False, contents=sse, display_type="danger", group_id="RBAC", slaveid=store.slaveid)
def add_log(self, log_name): """ Adds a log file to the merkyl process. This function adds a log file path to the merkyl process on the appliance. This is relevant only for the duration of the test. At the end of the test, the file is removed from the merkyl tracker. Note that this is a blocking call, ie, we ensure that the file is being logged by merkyl, before we continue. This is important and prevents the file_add operation being queued and processes which generate log information activating before the log is being monitored. This is achieved using the grab_result switch, but in fact, nothing will be received. It is worth noting that the file path must be "discoverable" by merkyl. This may mean editing the allowed_files prior to deploying merkyl. Args: log_name: Full path to the log file wishing to be monitored. """ fire_art_test_hook( self.node, 'add_log_merkyl', ip=self.ip, filename=log_name, grab_result=True)
def pytest_exception_interact(node, call, report): from cfme.fixtures.pytest_store import store from six.moves.http_client import BadStatusLine from socket import error val = safe_string(call.excinfo.value) if isinstance(call.excinfo.value, (URLError, BadStatusLine, error)): logger.error("internal Exception:\n %s", str(call.excinfo)) from cfme.utils.browser import manager manager.start() # start will quit first and cycle wharf as well last_lines = "\n".join(report.longreprtext.split("\n")[-4:]) short_tb = '{}\n{}\n{}'.format( last_lines, call.excinfo.type.__name__, val.encode('ascii', 'xmlcharrefreplace') ) fire_art_test_hook( node, 'filedump', description="Traceback", contents=report.longreprtext, file_type="traceback", display_type="danger", display_glyph="align-justify", group_id="pytest-exception", slaveid=store.slaveid) fire_art_test_hook( node, 'filedump', description="Short traceback", contents=short_tb, file_type="short_tb", display_type="danger", display_glyph="align-justify", group_id="pytest-exception", slaveid=store.slaveid) exception_name = call.excinfo.type.__name__ exception_lineno = call.excinfo.traceback[-1].lineno exception_filename = str(call.excinfo.traceback[-1].path).replace( project_path.strpath + "/", '' ) exception_location = "{}:{}".format(exception_filename, exception_lineno) fire_art_test_hook( node, 'tb_info', exception=exception_name, file_line=exception_location, short_tb=short_tb, slave_id=store.slaveid ) # base64 encoded to go into a data uri, same for screenshots tb = report.longreprtext if not isinstance(tb, six.binary_type): tb = tb.encode('utf-8') full_tb = base64.b64encode(tb) # errors are when exceptions are thrown outside of the test call phase report.when = getattr(report, 'when', 'setup') is_error = report.when != 'call' template_data = { 'name': node.name, 'file': node.fspath, 'is_error': is_error, 'fail_stage': report.when, 'short_tb': short_tb, 'full_tb': full_tb, } # Before trying to take a screenshot, we used to check if one of the browser_fixtures was # in this node's fixturenames, but that was too limited and preventing the capture of # screenshots. If removing that conditional now makes this too broad, we should consider # an isinstance(val, WebDriverException) check in addition to the browser fixture check that # exists here in commit 825ef50fd84a060b58d7e4dc316303a8b61b35d2 screenshot = take_screenshot() template_data['screenshot'] = screenshot.png template_data['screenshot_error'] = screenshot.error if screenshot.png: fire_art_test_hook( node, 'filedump', description="Exception screenshot", file_type="screenshot", mode="wb", contents_base64=True, contents=template_data['screenshot'], display_glyph="camera", group_id="pytest-exception", slaveid=store.slaveid) if screenshot.error: fire_art_test_hook( node, 'filedump', description="Screenshot error", mode="w", contents_base64=False, contents=template_data['screenshot_error'], display_type="danger", group_id="pytest-exception", slaveid=store.slaveid) failed_test_tracking['tests'].append(template_data) if is_error: failed_test_tracking['total_errored'] += 1 else: failed_test_tracking['total_failed'] += 1
def pytest_exception_interact(node, call, report): from cfme.fixtures.pytest_store import store from http.client import BadStatusLine from socket import error val = safe_string(call.excinfo.value) if isinstance(call.excinfo.value, (URLError, BadStatusLine, error)): logger.error("internal Exception:\n %s", str(call.excinfo)) from cfme.utils.browser import manager manager.start() # start will quit first and cycle wharf as well last_lines = "\n".join(report.longreprtext.split("\n")[-4:]) short_tb = '{}\n{}\n{}'.format(last_lines, call.excinfo.type.__name__, val.encode('ascii', 'xmlcharrefreplace')) fire_art_test_hook(node, 'filedump', description="Traceback", contents=report.longreprtext, file_type="traceback", display_type="danger", display_glyph="align-justify", group_id="pytest-exception", slaveid=store.slaveid) fire_art_test_hook(node, 'filedump', description="Short traceback", contents=short_tb, file_type="short_tb", display_type="danger", display_glyph="align-justify", group_id="pytest-exception", slaveid=store.slaveid) exception_name = call.excinfo.type.__name__ exception_lineno = call.excinfo.traceback[-1].lineno exception_filename = str(call.excinfo.traceback[-1].path).replace( project_path.strpath + "/", '') exception_location = f"{exception_filename}:{exception_lineno}" fire_art_test_hook(node, 'tb_info', exception=exception_name, file_line=exception_location, short_tb=short_tb, slave_id=store.slaveid) # base64 encoded to go into a data uri, same for screenshots tb = report.longreprtext if not isinstance(tb, bytes): tb = tb.encode('utf-8') full_tb = base64.b64encode(tb) # errors are when exceptions are thrown outside of the test call phase report.when = getattr(report, 'when', 'setup') is_error = report.when != 'call' template_data = { 'name': node.name, 'file': node.fspath, 'is_error': is_error, 'fail_stage': report.when, 'short_tb': short_tb, 'full_tb': full_tb, } # Before trying to take a screenshot, we used to check if one of the browser_fixtures was # in this node's fixturenames, but that was too limited and preventing the capture of # screenshots. If removing that conditional now makes this too broad, we should consider # an isinstance(val, WebDriverException) check in addition to the browser fixture check that # exists here in commit 825ef50fd84a060b58d7e4dc316303a8b61b35d2 screenshot = take_screenshot() template_data['screenshot'] = screenshot.png template_data['screenshot_error'] = screenshot.error if screenshot.png: fire_art_test_hook(node, 'filedump', description="Exception screenshot", file_type="screenshot", mode="wb", contents_base64=True, contents=template_data['screenshot'], display_glyph="camera", group_id="pytest-exception", slaveid=store.slaveid) if screenshot.error: fire_art_test_hook(node, 'filedump', description="Screenshot error", mode="w", contents_base64=False, contents=template_data['screenshot_error'], display_type="danger", group_id="pytest-exception", slaveid=store.slaveid) failed_test_tracking['tests'].append(template_data) if is_error: failed_test_tracking['total_errored'] += 1 else: failed_test_tracking['total_failed'] += 1