def _make_media_html_div( self, extra, extra_index, test_index, base_extra_string, base_extra_class ): content = extra.get("content") try: is_uri_or_path = content.startswith(("file", "http")) or isfile(content) except ValueError: # On Windows, os.path.isfile throws this exception when # passed a b64 encoded image. is_uri_or_path = False if is_uri_or_path: if self.self_contained: warnings.warn(f"独立的 HTML 报告, 包含所有外链资源,资源: {content}") html_div = html.a( raw(base_extra_string.format(extra.get("content"))), href=content ) elif self.self_contained: src = f"data:{extra.get('mime_type')};base64,{content}" html_div = raw(base_extra_string.format(src)) else: content = b64decode(content.encode("utf-8")) href = src = self.create_asset( content, extra_index, test_index, extra.get("extension"), "wb" ) html_div = html.a( raw(base_extra_string.format(src)), class_=base_extra_class, target="_blank", href=href, ) return html_div
def make_html_report(path, report): def tabelize(value): try: rows = [] for key in value.keys(): rows.append(html.tr(html.td(html.pre(key)), html.td(tabelize(value[key])))) return html.table(rows) except AttributeError: if type(value) == type([]): return html.table(map(tabelize, value)) else: return html.pre(value) body_els = [] keys = report.keys() keys.sort() links = [] for key in keys: links.append(html.li(html.a(key, href="#" + key))) body_els.append(html.ul(links)) for key in keys: body_els.append(html.a(html.h1(key), id=key)) body_els.append(tabelize(report[key])) with open(path, 'w') as f: doc = html.html(html.head(html.style('table, td {border: 1px solid;}')), html.body(body_els)) f.write(str(doc))
def make_html_report(path, report): def tabelize(value): try: rows = [] for key in value.keys(): rows.append( html.tr(html.td(html.pre(key)), html.td(tabelize(value[key])))) return html.table(rows) except AttributeError: if type(value) == type([]): return html.table(map(tabelize, value)) else: return html.pre(value) body_els = [] keys = report.keys() keys.sort() links = [] for key in keys: links.append(html.li(html.a(key, href="#" + key))) body_els.append(html.ul(links)) for key in keys: body_els.append(html.a(html.h1(key), id=key)) body_els.append(tabelize(report[key])) with open(path, 'w') as f: doc = html.html( html.head(html.style('table, td {border: 1px solid;}')), html.body(body_els)) f.write(str(doc))
def append_extra_html(self, extra, additional_html, links_html): href = None if extra.get('format') == extras.FORMAT_IMAGE: href = '#' image = 'data:image/png;base64,{0}'.format( extra.get('content')) additional_html.append(html.div( html.a(html.img(src=image), href="#"), class_='image')) elif extra.get('format') == extras.FORMAT_HTML: additional_html.append(html.div(raw(extra.get('content')))) elif extra.get('format') == extras.FORMAT_JSON: href = data_uri(json.dumps(extra.get('content')), mime_type='application/json') elif extra.get('format') == extras.FORMAT_TEXT: href = data_uri(extra.get('content')) elif extra.get('format') == extras.FORMAT_URL: href = extra.get('content') if href is not None: links_html.append(html.a( extra.get('name'), class_=extra.get('format'), href=href, target='_blank')) links_html.append(' ')
def _appendrow(self, result, report): time = getattr(report, 'duration', 0.0) additional_html = [] links_html = [] for extra in getattr(report, 'extra', []): href = None if extra.get('format') == extras.FORMAT_IMAGE: href = '#' image = 'data:image/png;base64,%s' % extra.get('content') additional_html.append(html.div( html.a(html.img(src=image), href="#"), class_='image')) elif extra.get('format') == extras.FORMAT_HTML: additional_html.append(extra.get('content')) elif extra.get('format') == extras.FORMAT_JSON: href = data_uri(json.dumps(extra.get('content')), mime_type='application/json') elif extra.get('format') == extras.FORMAT_TEXT: href = data_uri(extra.get('content')) elif extra.get('format') == extras.FORMAT_URL: href = extra.get('content') if href is not None: links_html.append(html.a( extra.get('name'), class_=extra.get('format'), href=href, target='_blank')) links_html.append(' ') if 'Passed' not in result: if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): if not PY3: line = line.decode('utf-8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(escape(line)), class_='error')) else: log.append(raw(escape(line))) log.append(html.br()) additional_html.append(log) self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(report.nodeid, class_='col-name'), html.td('%.2f' % time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='extra')], class_=result.lower() + ' results-table-row'))
def make_result_html(self, data): tc_time = (data["time"] - self.start_times.pop(data["test"])) / 1000. additional_html = [] debug = data.get("extra", {}) links_html = [] status = status_name = data["status"] expected = data.get("expected", status) if status != expected: status_name = "UNEXPECTED_" + status elif status != "PASS": status_name = "EXPECTED_" + status self.test_count[status_name] += 1 if status in ['SKIP', 'FAIL', 'ERROR']: if debug.get('screenshot'): screenshot = 'data:image/png;base64,%s' % debug['screenshot'] additional_html.append(html.div( html.a(html.img(src=screenshot), href="#"), class_='screenshot')) for name, content in debug.items(): if 'screenshot' in name: href = '#' else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(content.encode('utf-8')) links_html.append(html.a( name.title(), class_=name, href=href, target='_blank')) links_html.append(' ') log = html.div(class_='log') output = data.get('stack', '').splitlines() output.extend(data.get('message', '').splitlines()) for line in output: separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) self.result_rows.append( html.tr([html.td(status_name, class_='col-result'), html.td(data['test'], class_='col-name'), html.td('%.2f' % tc_time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug')], class_=status_name.lower() + ' results-table-row'))
def fill(self): super(HPage, self).fill() self.menubar[:] = html.ul( html.li(html.a("home", href="index.html", class_="menu")), html.li(html.a("install", href="install.html", class_="menu")), html.li(html.a("usage", href="usage.html", class_="menu")), id="menubar", )
def append_extra_html(self, extra, extra_index, test_index): href = None if extra.get('format') == extras.FORMAT_IMAGE: content = extra.get('content') if content.startswith(('file', 'http')) or \ os.path.isfile(content): if self.self_contained: warnings.warn('Self-contained HTML report ' 'includes link to external ' 'resource: {}'.format(content)) html_div = html.a(html.img(src=content), href=content) elif self.self_contained: src = 'data:{0};base64,{1}'.format(extra.get('mime_type'), content) html_div = html.img(src=src) else: if PY3: content = b64decode(content.encode('utf-8')) else: content = b64decode(content) href = src = self.create_asset(content, extra_index, test_index, extra.get('extension'), 'wb') html_div = html.a(html.img(src=src), href=href) self.additional_html.append(html.div(html_div, class_='image')) elif extra.get('format') == extras.FORMAT_HTML: self.additional_html.append(html.div(raw( extra.get('content')))) elif extra.get('format') == extras.FORMAT_JSON: content = json.dumps(extra.get('content')) if self.self_contained: href = data_uri(content, mime_type=extra.get('mime_type')) else: href = self.create_asset(content, extra_index, test_index, extra.get('extension')) elif extra.get('format') == extras.FORMAT_TEXT: content = extra.get('content') if self.self_contained: href = data_uri(content) else: href = self.create_asset(content, extra_index, test_index, extra.get('extension')) elif extra.get('format') == extras.FORMAT_URL: href = extra.get('content') if href is not None: self.links_html.append( html.a(extra.get('name'), class_=extra.get('format'), href=href, target='_blank')) self.links_html.append(' ')
def _appendrow(self, result, report): time = getattr(report, 'duration', 0.0) additional_html = [] links_html = [] if 'Passed' not in result: for extra in getattr(report, 'extra', []): href = None if type(extra) is Image: href = '#' image = 'data:image/png;base64,%s' % extra.content additional_html.append(html.div( html.a(html.img(src=image), href="#"), class_='image')) elif type(extra) is HTML: additional_html.append(extra.content) elif type(extra) is Text: href = 'data:text/plain;charset=utf-8;base64,%s' % \ b64encode(extra.content) elif type(extra) is URL: href = extra.content if href is not None: links_html.append(html.a( extra.name, class_=extra.__class__.__name__.lower(), href=href, target='_blank')) links_html.append(' ') if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): line = line.decode('utf-8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(report.nodeid, class_='col-name'), html.td('%.2f' % time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='extra')], class_=result.lower() + ' results-table-row'))
def _extract_html(test, class_name, duration=0, text='', result='passed', debug=None): cls_name = class_name tc_name = unicode(test) tc_time = duration additional_html = [] debug = debug or {} links_html = [] if result in ['skipped', 'failure', 'expected failure', 'error']: if debug.get('screenshot'): screenshot = 'data:image/png;base64,%s' % debug['screenshot'] additional_html.append(html.div( html.a(html.img(src=screenshot), href="#"), class_='screenshot')) for name, content in debug.items(): try: if 'screenshot' in name: href = '#' else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(content) links_html.append(html.a( name.title(), class_=name, href=href, target='_blank')) links_html.append(' ') except: pass log = html.div(class_='log') for line in text.splitlines(): separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) test_logs.append(html.tr([ html.td(result.title(), class_='col-result'), html.td(cls_name, class_='col-class'), html.td(tc_name, class_='col-name'), html.td(tc_time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug')], class_=result.lower() + ' results-table-row'))
def append_extra_html(self, extra, extra_index, test_index): href = None if extra.get('format') == extras.FORMAT_IMAGE: if self.self_contained: src = 'data:{0};base64,{1}'.format(extra.get('mime_type'), extra.get('content')) self.additional_html.append( html.div(html.img(src=src), class_='image')) else: content = extra.get('content') if PY3: content = b64decode(content.encode('utf-8')) else: content = b64decode(content) href = src = self.create_asset(content, extra_index, test_index, extra.get('extension'), 'wb') self.additional_html.append( html.div(html.a(html.img(src=src), href=href), class_='image')) elif extra.get('format') == extras.FORMAT_HTML: self.additional_html.append(html.div(raw( extra.get('content')))) elif extra.get('format') == extras.FORMAT_JSON: content = json.dumps(extra.get('content')) if self.self_contained: href = data_uri(content, mime_type=extra.get('mime_type')) else: href = self.create_asset(content, extra_index, test_index, extra.get('extension')) elif extra.get('format') == extras.FORMAT_TEXT: content = extra.get('content') if self.self_contained: href = data_uri(content) else: href = self.create_asset(content, extra_index, test_index, extra.get('extension')) elif extra.get('format') == extras.FORMAT_URL: href = extra.get('content') if href is not None: self.links_html.append( html.a(extra.get('name'), class_=extra.get('format'), href=href, target='_blank')) self.links_html.append(' ')
def _extract_html(test, class_name, duration=0, text="", result="passed", debug=None): cls_name = class_name tc_name = unicode(test) tc_time = duration additional_html = [] debug = debug or {} links_html = [] if result in ["skipped", "failure", "expected failure", "error"]: if debug.get("screenshot"): screenshot = "data:image/png;base64,%s" % debug["screenshot"] additional_html.append(html.div(html.a(html.img(src=screenshot), href="#"), class_="screenshot")) for name, content in debug.items(): try: if "screenshot" in name: href = "#" else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = "data:text/plain;charset=utf-8;base64,%s" % base64.b64encode(content) links_html.append(html.a(name.title(), class_=name, href=href, target="_blank")) links_html.append(" ") except: pass log = html.div(class_="log") for line in text.splitlines(): separator = line.startswith(" " * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_="error")) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) test_logs.append( html.tr( [ html.td(result.title(), class_="col-result"), html.td(cls_name, class_="col-class"), html.td(tc_name, class_="col-name"), html.td(tc_time, class_="col-duration"), html.td(links_html, class_="col-links"), html.td(additional_html, class_="debug"), ], class_=result.lower() + " results-table-row", ) )
def suite_start(self, data): self.suite_times["start"] = data["time"] self.suite_name = data["source"] with open(os.path.join(base_path, "style.css")) as f: self.head = html.head(html.meta(charset="utf-8"), html.title(data["source"]), html.style(raw(f.read()))) date_format = "%d %b %Y %H:%M:%S" version_info = data.get("version_info") if version_info: self.env["Device identifier"] = version_info.get("device_id") self.env["Device firmware (base)"] = version_info.get( "device_firmware_version_base") self.env["Device firmware (date)"] = (datetime.utcfromtimestamp( int(version_info.get("device_firmware_date"))).strftime( date_format) if "device_firmware_date" in version_info else None) self.env["Device firmware (incremental)"] = version_info.get( "device_firmware_version_incremental") self.env["Device firmware (release)"] = version_info.get( "device_firmware_version_release") self.env["Gaia date"] = (datetime.utcfromtimestamp( int(version_info.get("gaia_date"))).strftime(date_format) if "gaia_date" in version_info else None) self.env["Gecko version"] = version_info.get("application_version") self.env["Gecko build"] = version_info.get("application_buildid") if version_info.get("application_changeset"): self.env["Gecko revision"] = version_info.get( "application_changeset") if version_info.get("application_repository"): self.env["Gecko revision"] = html.a( version_info.get("application_changeset"), href="/".join([ version_info.get("application_repository"), version_info.get("application_changeset") ]), target="_blank") if version_info.get("gaia_changeset"): self.env["Gaia revision"] = html.a( version_info.get("gaia_changeset")[:12], href="https://github.com/mozilla-b2g/gaia/commit/%s" % version_info.get("gaia_changeset"), target="_blank") device_info = data.get("device_info") if device_info: self.env["Device uptime"] = device_info.get("uptime") self.env["Device memory"] = device_info.get("memtotal") self.env["Device serial"] = device_info.get("id")
def test_prepare_line_basic(): result = prepare_line_helper(['see if this works']) assert result == 'see <span class="keyword">if</span> this works' result = prepare_line_helper(['see if this ', html.a('works', name='works'),' too']) assert result == ('see <span class="keyword">if</span> this ' '<a name="works">works</a> too') result = prepare_line_helper(['see if something else works']) assert result == ('see <span class="keyword">if</span> something ' '<span class="keyword">else</span> works') result = prepare_line_helper(['see if something ', html.a('else', name='else'), ' works too']) assert result == ('see <span class="keyword">if</span> something ' '<a name="else">else</a> works too')
def make_table_rows(self, results): rv = [] for key in results.keys(): result = results[key]['results'] cells = [html.td(key, class_="col-subsuite")] if result.has_errors: cells.append( html.td( len(result.errors), class_="condition FAIL col-subsuite", )) else: cells.append(html.td("0", class_="condition PASS")) style = '' if result.has_fails or result.has_errors: style = 'background-color: darkblue;' if result.has_regressions: num_regressions = sum( len(item) for item in result.regressions.itervalues()) cells.append( html.td(num_regressions, class_="condition PASS", style=style)) else: cells.append(html.td("0", class_="condition PASS")) details_link = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode( results[key]['html_str']) ulbody = [ html.li( html.a("subsuite report", href=details_link, target='_blank')) ] files = results[key]['files'] for fname in files.keys(): href = '%s/%s' % (key, fname) #if key[-4:] == 'html' or key[-3:] == 'htm': # href = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode(files[key]) #else: # href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(files[key]) ulbody.append( html.li(html.a(fname, href=href, target='_blank'))) cells.append(html.td(html.ul(ulbody), class_="details")) rv.append(html.tr(cells, class_='results-table-row')) return rv
def simple_list_project(self, user, index, projectname): # we only serve absolute links so we don't care about the route's slash stage = self.getstage(user, index) result = stage.getreleaselinks(projectname) if isinstance(result, int): if result == 404: abort(404, "no such project") if result >= 500: abort(502, "upstream server has internal error") if result < 0: abort(502, "upstream server not reachable") links = [] for entry in result: href = "/pkg/" + entry.relpath if entry.eggfragment: href += "#egg=%s" % entry.eggfragment elif entry.md5: href += "#md5=%s" % entry.md5 links.append((href, entry.basename)) # construct html body = [] for entry in links: body.append(html.a(entry[1], href=entry[0])) body.append(html.br()) return simple_html_body("%s: links for %s" % (stage.name, projectname), body).unicode()
def _generate_environment(self, config): if not hasattr(config, "_metadata") or config._metadata is None: return [] metadata = config._metadata environment = [html.h2("Environment")] rows = [] keys = [k for k in metadata.keys()] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, str) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join(str(i) for i in sorted(map(str, value))) elif isinstance(value, dict): key_value_list = [f"'{k}': {value[k]}" for k in sorted(value)] value = ", ".join(key_value_list) value = "{" + value + "}" raw_value_string = raw(str(value)) rows.append(html.tr(html.td(key), html.td(raw_value_string))) environment.append(html.table(rows, id="environment")) return environment
def _link_to_debug_event(self, name, log): name = re.sub('[^A-Za-z0-9_.]+', '_', name) browser_name = self.prefix.split(",")[0].replace('[', '').lower() source = os.path.join(self.project_root, 'debug_events', browser_name + '_' + name + '.json') self.used_debug_events.append(source) return [html.a("Console log", href='debug_events/' + browser_name + '_' + name + '.json'), ' ']
def make_table_rows(self, results): rv = [] for result in results: details_link = "%s/report.html" % result.name cells = [html.td(result.name)] if result.has_errors: cells.append(html.td( len(result.errors), class_="condition FAIL", )) else: cells.append(html.td("0", class_="condition PASS")) if result.has_regressions: num_regressions = sum(len(item) for item in result.regressions.itervalues()) cells.append(html.td(num_regressions, class_="condition FAIL")) else: cells.append(html.td("0", class_="condition PASS")) if result.is_pass: cells.append(html.td()) else: cells.append(html.td( html.a("details", href=details_link), class_="details" )) rv.append(html.tr(cells)) return rv
def _generate_environment(self, config): if not hasattr(config, "_metadata") or config._metadata is None: return [] metadata = config._metadata if 'Capabilities' in metadata: metadata.pop('Capabilities') if 'Base URL' in config._metadata: metadata.pop('Base URL') environment = [html.h2("Environment")] rows = [] keys = [k for k in metadata.keys()] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, str) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join(str(i) for i in value) rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id="environment")) return environment
def pytest_html_results_table_row(report, cells): """ Inserts the contents for the 'description' column : the docstring of the test function """ node_bits = report.nodeid.split('::') file = node_bits[0] test_id = node_bits[1:] line = report.location[1] cells[1] = html.th(file) cells.insert(2, html.td('::'.join(test_id) if len(node_bits) > 1 else '')) cells.insert(3, html.td(report.description)) # cells.insert(1, html.td(datetime.utcnow(), class_='col-time')) # cells.pop() # use setuptools_scm to get git hash and build the codecov URL to go and see the source of the test # parsed_version = version_from_scm('.') # if parsed_version is not None: # hsh = parsed_version.node + ('' if not parsed_version.dirty else '-dirty') try: hsh = get_git_hash() cells[-1] = html.td( html.a('source', href='https://codecov.io/gh/smarie/python-valid8/src/' + hsh + '/' + file + '#L' + str(line))) except: cells[-1] = html.td('could not read git version')
def pytest_html_results_table_row(report, cells): waveform = html.td("N/A") if report.trace: waveform = html.td(html.a("waveform-trace", href=report.trace)) cells.insert(2, waveform) cells.pop()
def _generate_environment(self, environment_details): rows = [] keys = [ k for k in environment_details.keys() if environment_details[k] ] if not isinstance(environment_details, OrderedDict): keys.sort() for key in keys: value = environment_details[key] if isinstance(value, basestring) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join((str(i) for i in value)) rows.append(html.tr(html.td(key), html.td(value))) environment = html.div( html.h2("Environment"), html.div( html.table(rows, id="environment"), class_="environment-info", ), class_="environment-details", ) return environment
def _generate_environment(self, config): if not hasattr(config, "_metadata") or config._metadata is None: return [] metadata = config._metadata environment = [html.h2("测试环境")] rows = [] keys = [k for k in metadata.keys()] # if not isinstance(metadata, OrderedDict): # keys.sort() for key in keys: value = metadata[key] if isinstance(value, str) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join(str(i) for i in sorted(map(str, value))) elif isinstance(value, dict): sorted_dict = {k: value[k] for k in sorted(value)} value = json.dumps(sorted_dict) raw_value_string = raw(str(value)) rows.append(html.tr(html.td(TEST_ENV.get(key)), html.td(raw_value_string))) environment.append(html.table(rows, id="environment")) return environment
def simple_list_project(self, user, index, projectname): # we only serve absolute links so we don't care about the route's slash abort_if_invalid_projectname(projectname) stage = self.getstage(user, index) projectname = ensure_unicode(projectname) info = stage.get_project_info(projectname) if info and info.name != projectname: redirect("/%s/+simple/%s/" % (stage.name, info.name)) result = stage.getreleaselinks(projectname) if isinstance(result, int): if result == 404: # we don't want pip/easy_install to try the whole simple # page -- we know for sure there is no fitting project # because all devpi indexes perform package name normalization abort(200, "no such project %r" % projectname) if result >= 500: abort(502, "upstream server has internal error") if result < 0: abort(502, "upstream server not reachable") links = [] for entry in result: relpath = entry.relpath href = "/" + relpath href = URL(request.path).relpath(href) if entry.eggfragment: href += "#egg=%s" % entry.eggfragment elif entry.md5: href += "#md5=%s" % entry.md5 links.extend([ "/".join(relpath.split("/", 2)[:2]) + " ", html.a(entry.basename, href=href), html.br(), "\n", ]) return simple_html_body("%s: links for %s" % (stage.name, projectname), links).unicode(indent=2)
def suite_start(self, data): self.suite_times["start"] = data["time"] self.suite_name = data["source"] with open(os.path.join(base_path, "style.css")) as f: self.head = html.head( html.meta(charset="utf-8"), html.title(data["source"]), html.style(raw(f.read()))) date_format = "%d %b %Y %H:%M:%S" version_info = data.get("version_info") if version_info: self.env["Device identifier"] = version_info.get("device_id") self.env["Device firmware (base)"] = version_info.get("device_firmware_version_base") self.env["Device firmware (date)"] = ( datetime.utcfromtimestamp(int(version_info.get("device_firmware_date"))).strftime(date_format) if "device_firmware_date" in version_info else None) self.env["Device firmware (incremental)"] = version_info.get("device_firmware_version_incremental") self.env["Device firmware (release)"] = version_info.get("device_firmware_version_release") self.env["Gaia date"] = ( datetime.utcfromtimestamp(int(version_info.get("gaia_date"))).strftime(date_format) if "gaia_date" in version_info else None) self.env["Gecko version"] = version_info.get("application_version") self.env["Gecko build"] = version_info.get("application_buildid") if version_info.get("application_changeset"): self.env["Gecko revision"] = version_info.get("application_changeset") if version_info.get("application_repository"): self.env["Gecko revision"] = html.a( version_info.get("application_changeset"), href="/".join([version_info.get("application_repository"), version_info.get("application_changeset")]), target="_blank") if version_info.get("gaia_changeset"): self.env["Gaia revision"] = html.a( version_info.get("gaia_changeset")[:12], href="https://github.com/mozilla-b2g/gaia/commit/%s" % version_info.get("gaia_changeset"), target="_blank") device_info = data.get("device_info") if device_info: self.env["Device uptime"] = device_info.get("uptime") self.env["Device memory"] = device_info.get("memtotal") self.env["Device serial"] = device_info.get("id")
def simple_list_all(self, user, index): stage = self.getstage(user, index) names = stage.getprojectnames() body = [] for name in names: body.append(html.a(name, href=name + "/")) body.append(html.br()) return simple_html_body("%s: list of accessed projects" % stage.name, body).unicode()
def _link_to_browserstack_log(self, output): info = output.split(" ") link_html = [] for i in range(0, len(info)): match_obj = re.search(r'(https?://www.browserstack.com/automate/builds/[\w]*/sessions/[\w]*)/', info[i]) if match_obj: link_html.append(html.a("Browserstack", href=match_obj.group(1), target='_blank')) link_html.append(' ') return link_html
def simple_list_project(self): request = self.request name = self.context.name # we only serve absolute links so we don't care about the route's slash abort_if_invalid_projectname(request, name) stage = self.context.stage if stage.get_projectname(name) is None: # we return 200 instead of !=200 so that pip/easy_install don't # ask for the full simple page although we know it doesn't exist # XXX change that when pip-6.0 is released? abort(request, 200, "no such project %r" % name) projectname = self.context.projectname try: result = stage.get_releaselinks(projectname) except stage.UpstreamError as e: threadlog.error(e.msg) abort(request, 502, e.msg) links = [] for link in result: relpath = link.entrypath href = "/" + relpath href = URL(request.path_info).relpath(href) if link.eggfragment: href += "#egg=%s" % link.eggfragment elif link.hash_spec: href += "#" + link.hash_spec links.extend([ "/".join(relpath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n", ]) title = "%s: links for %s" % (stage.name, projectname) if stage.has_pypi_base(projectname): refresh_title = "Refresh" if stage.ixconfig["type"] == "mirror" else \ "Refresh PyPI links" refresh_url = request.route_url( "/{user}/{index}/+simple/{name}/refresh", user=self.context.username, index=self.context.index, name=projectname) refresh_form = [ html.form( html.input( type="submit", value=refresh_title, name="refresh"), action=refresh_url, method="post"), "\n"] else: refresh_form = [] return Response(html.html( html.head( html.title(title)), html.body( html.h1(title), "\n", refresh_form, links)).unicode(indent=2))
def indexroot(self, user, index): stage = self.getstage(user, index) bases = html.ul() for base in stage.ixconfig["bases"]: bases.append(html.li( html.a("%s" % base, href="/%s/" % base), " (", html.a("simple", href="/%s/simple/" % base), " )", )) if bases: bases = [html.h2("inherited bases"), bases] return simple_html_body("%s index" % stage.name, [ html.ul( html.li(html.a("simple index", href="simple/")), ), bases, ]).unicode()
def make_body(self): body_parts = [ html.div( html.script(raw( pkg_resources.resource_string( rcname, os.path.sep.join( ['resources', 'htmlreport', 'jquery.js']))), type='text/javascript'), html.script(raw( pkg_resources.resource_string( rcname, os.path.sep.join( ['resources', 'htmlreport', 'main.js']))), type='text/javascript'), html.h1("FirefoxOS Certification Suite Report"), html.p("Run at %s" % self.time.strftime("%Y-%m-%d %H:%M:%S"))) ] if self.logs: device_profile_object = None with open(self.logs[-1]) as f: device_profile_object = json.load(f)['result']['contact'] device_profile = [html.h2('Device Information')] device_table = html.table() for key in device_profile_object: device_table.append( html.tr(html.td(key), html.td(device_profile_object[key]))) #device_profile.append(html.p("%s, %s"% (key, device_profile_object[key]))) device_profile.append(device_table) body_parts.extend(device_profile) if self.summary_results.has_errors: body_parts.append(html.h2("Errors During Run")) body_parts.append( self.make_errors_table(self.summary_results.errors)) body_parts.append(html.h2("Test Results")) body_parts.append(self.make_result_table()) if self.logs: ulbody = [] for log_path in self.logs: details_log = '' with open(log_path, 'r') as f: details_log = f.read() href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode( details_log) ulbody.append( html.li( html.a(os.path.basename(log_path), href=href, target='_blank'))) device_profile_object = None body_parts.append(html.h2("Details log information")) body_parts.append(html.ul(ulbody)) return html.body(body_parts)
def simple_list_project(self): request = self.request name = self.context.name # we only serve absolute links so we don't care about the route's slash abort_if_invalid_projectname(request, name) stage = self.context.stage projectname = stage.get_projectname(name) if projectname is None: abort(request, 200, "no such project %r" % projectname) if name != projectname: redirect("/%s/+simple/%s/" % (stage.name, projectname)) try: result = stage.get_releaselinks(projectname) except stage.UpstreamError as e: threadlog.error(e.msg) abort(request, 502, e.msg) links = [] for link in result: relpath = link.entrypath href = "/" + relpath href = URL(request.path).relpath(href) if link.eggfragment: href += "#egg=%s" % link.eggfragment elif link.md5: href += "#md5=%s" % link.md5 links.extend([ "/".join(relpath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n", ]) title = "%s: links for %s" % (stage.name, projectname) if stage.has_pypi_base(projectname): refresh_title = "Refresh" if stage.ixconfig["type"] == "mirror" else \ "Refresh PyPI links" refresh_url = request.route_url( "/{user}/{index}/+simple/{name}/refresh", user=self.context.username, index=self.context.index, name=projectname) refresh_form = [ html.form( html.input( type="submit", value=refresh_title, name="refresh"), action=refresh_url, method="post"), "\n"] else: refresh_form = [] return Response(html.html( html.head( html.title(title)), html.body( html.h1(title), "\n", refresh_form, links)).unicode(indent=2))
def simple_list_project(self): request = self.request name = self.context.name # we only serve absolute links so we don't care about the route's slash abort_if_invalid_projectname(request, name) stage = self.context.stage projectname = stage.get_projectname(name) if projectname is None: abort(request, 200, "no such project %r" % projectname) if name != projectname: redirect("/%s/+simple/%s/" % (stage.name, projectname)) try: result = stage.get_releaselinks(projectname) except stage.UpstreamError as e: threadlog.error(e.msg) abort(request, 502, e.msg) links = [] for link in result: relpath = link.entrypath href = "/" + relpath href = URL(request.path).relpath(href) if link.eggfragment: href += "#egg=%s" % link.eggfragment elif link.md5: href += "#md5=%s" % link.md5 links.extend([ "/".join(relpath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n", ]) title = "%s: links for %s" % (stage.name, projectname) if stage.has_pypi_base(projectname): refresh_title = "Refresh" if stage.ixconfig["type"] == "mirror" else \ "Refresh PyPI links" refresh_url = request.route_url( "/{user}/{index}/+simple/{name}/refresh", user=self.context.username, index=self.context.index, name=projectname) refresh_form = [ html.form(html.input(type="submit", value=refresh_title, name="refresh"), action=refresh_url, method="post"), "\n" ] else: refresh_form = [] return Response( html.html(html.head(html.title(title)), html.body(html.h1(title), "\n", refresh_form, links)).unicode(indent=2))
def breadcrumb(self, title): if title != 'index': type, path = title.split('_', 1) path = path.split('.') module = None cls = None func = None meth = None if type == 'module': module = '.'.join(path) elif type == 'class': module = '.'.join(path[:-1]) cls = path[-1] elif type == 'method': module = '.'.join(path[:-2]) cls = path[-2] meth = path[-1] else: module = '.'.join(path[:-1]) func = path[-1] if module: yield html.a(module, href='module_%s.html' % (module,)) if type != 'module': yield u'.' if cls: s = cls if module: s = '%s.%s' % (module, cls) yield html.a(cls, href='class_%s.html' % (s,)) if type != 'class': yield u'.' if meth: s = '%s.%s' % (cls, meth) if module: s = '%s.%s.%s' % (module, cls, meth) yield html.a(meth, href='method_%s.html' % (s,)) if func: s = func if module: s = '%s.%s' % (module, func) yield html.a(func, href='function_%s.html' % (s,))
def _append_xpass_section(log, report): log.append(html.h3('Expected failure')) xfail_p = html.p(class_='xfail') xfail_reason = report.wasxfail xfail_p.append("Reason: ") # Does xfail reason contain e.g. link to JIRA? urls = find_urls(xfail_reason) if len(urls) > 0: xfail_p.append(html.a(xfail_reason, href=urls[0], target='_blank')) else: xfail_p.append(xfail_reason) log.append(xfail_p)
def _appendrow(self, result, report): names = mangle_testnames(report.nodeid.split("::")) testclass = (names[:-1]) if self.prefix: testclass.insert(0, self.prefix) testclass = ".".join(testclass) testmethod = names[-1] time = getattr(report, 'duration', 0.0) additional_html = [] if not 'Passed' in result: if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): line = line.decode('utf8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append( html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) if not os.path.exists(self.screenshot_path): os.makedirs(self.screenshot_path) self.append_screenshot(testmethod, log) additional_html.append(log) output = self._write_captured_output(report) info = output.split(" ") links_html = [] for i in range(0, len(info)): if ("http" in info[i] and "browserstack.com" in info[i]): links_html.append(html.a("link", href=info[i], target='_blank')) links_html.append(' ') self.test_logs.append( html.tr([ html.td(result, class_='col-result'), html.td(testclass, class_='col-class'), html.td(testmethod, class_='col-name'), html.td(round(time), class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug') ], class_=result.lower() + ' results-table-row'))
def make_table_rows(self, results): rv = [] for key in results.keys(): result = results[key]['results'] cells = [html.td(key, class_="col-subsuite")] if result.has_errors: cells.append(html.td( len(result.errors), class_="condition FAIL col-subsuite", )) else: cells.append(html.td("0", class_="condition PASS")) style = '' if result.has_fails or result.has_errors: style = 'background-color: darkblue;' if result.has_regressions: num_regressions = sum(len(item) for item in result.regressions.itervalues()) cells.append(html.td(num_regressions, class_="condition PASS", style=style)) else: cells.append(html.td("0", class_="condition PASS")) details_link = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode(results[key]['html_str']) ulbody = [html.li(html.a("subsuite report", href=details_link, target='_blank'))] files = results[key]['files'] for fname in files.keys(): href = '%s/%s' % (key, fname) #if key[-4:] == 'html' or key[-3:] == 'htm': # href = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode(files[key]) #else: # href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(files[key]) ulbody.append(html.li(html.a(fname, href=href, target='_blank'))) cells.append(html.td(html.ul(ulbody), class_="details")) rv.append(html.tr(cells, class_='results-table-row')) return rv
def enchant_row(self, num, row): # add some informations to row, like functions defined in that # line, etc. try: item = self.linecache[num] # XXX: this should not be assertion, rather check, but we want to # know if stuff is working pos = row.find(item.name) assert pos != -1 end = len(item.name) + pos chunk = html.a(row[pos:end], href="#" + item.listnames(), name=item.listnames()) return [row[:pos], chunk, row[end:]] except KeyError: return [row] # no more info
def _generate_s3_report(s3_data: dict): s3_link = s3_data['S3Link'] s3_data.pop('S3Link') file_results = [ html.p(item) for item in s3_data['FileResults'] if not item.endswith('/') ] s3_report = html.tr([ html.th(f'S3 results:', class_='s3-results'), html.th( *file_results, html.p(html.a(s3_link, href=s3_link)), ) ]) return s3_report
def make_body(self): body_parts = [html.div( html.script(raw(pkg_resources.resource_string( rcname, os.path.sep.join(['resources', 'htmlreport', 'jquery.js']))), type='text/javascript'), html.script(raw(pkg_resources.resource_string( rcname, os.path.sep.join(['resources', 'htmlreport', 'main.js']))), type='text/javascript'), html.h1("FirefoxOS Certification Suite Report"), html.p("Run at %s" % self.time.strftime("%Y-%m-%d %H:%M:%S")) )] if self.logs: device_profile_object = None with open(self.logs[-1]) as f: device_profile_object = json.load(f)['result']['contact'] device_profile = [html.h2('Device Information')] device_table = html.table() for key in device_profile_object: device_table.append( html.tr( html.td(key), html.td(device_profile_object[key]) ) ) #device_profile.append(html.p("%s, %s"% (key, device_profile_object[key]))) device_profile.append(device_table) body_parts.extend(device_profile); if self.summary_results.has_errors: body_parts.append(html.h2("Errors During Run")) body_parts.append(self.make_errors_table(self.summary_results.errors)) body_parts.append(html.h2("Test Results")) body_parts.append(self.make_result_table()) if self.logs: ulbody = []; for log_path in self.logs: details_log = '' with open(log_path, 'r') as f: details_log = f.read() href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(details_log) ulbody.append(html.li(html.a(os.path.basename(log_path), href=href, target='_blank'))) device_profile_object = None body_parts.append(html.h2("Details log information")) body_parts.append(html.ul(ulbody)) return html.body(body_parts)
def _generate_environment(self, config): if not hasattr(config, '_metadata') or config._metadata is None: return [] metadata = config._metadata environment = [html.h2('Environment')] rows = [] for key in [k for k in sorted(metadata.keys()) if metadata[k]]: value = metadata[key] if isinstance(value, basestring) and value.startswith('http'): value = html.a(value, href=value, target='_blank') rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id='environment')) return environment
def _generate_body(self, results_tree): body = html.body(onload="init()") generated_time = datetime.datetime.strptime( results_tree["suite_info"]["generated"].split(".")[0], "%Y-%I-%dT%X", ) summary_div = [ html.div( html.div(results_tree["name"], class_="project-title"), html.div( html.p('Report generated on {0} at {1} by'.format( generated_time.strftime('%d-%b-%Y'), generated_time.strftime('%H:%M:%S')), html.a(' pytest-html', href=__pypi_url__), ' v{0}'.format(__version__), class_="generated-time"), class_="generated-info", ), self._generate_environment( results_tree["suite_info"]["environment"], ), self._generate_summary_count( results_tree["suite_info"]["numtests"], results_tree["summary"], results_tree["suite_info"]["run_time"], ), class_="project-test-results-summary", ) ] self.config.hook.pytest_html_results_summary(summary=summary_div) results_div = [ html.div( html.h2("Results"), html.div( html.button("expand all", id="expand-all-button"), html.button("collapse all", id="collapse-all-button"), class_="show-hide-buttons", ), html.div(class_="results-info"), class_="results-details", ) ] body.extend([ summary_div, results_div, ]) return body
def _appendrow(self, result, report): names = mangle_testnames(report.nodeid.split("::")) testclass = (names[:-1]) if self.prefix: testclass.insert(0, self.prefix) testclass = ".".join(testclass) testmethod = names[-1] time = getattr(report, 'duration', 0.0) additional_html = [] if not 'Passed' in result: if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): line = line.decode('utf8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) if not os.path.exists(self.screenshot_path): os.makedirs(self.screenshot_path) self.append_screenshot(testmethod, log) additional_html.append(log) output = self._write_captured_output(report) info = output.split(" ") links_html = [] for i in range(0, len(info)): if ("http" in info[i] and "browserstack.com" in info[i]): links_html.append(html.a("link", href=info[i], target='_blank')) links_html.append(' ') self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(testclass, class_='col-class'), html.td(testmethod, class_='col-name'), html.td(round(time), class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug')], class_=result.lower() + ' results-table-row'))
def create_dir_html(path, href_prefix=''): h = html.html( html.head( html.title('directory listing of %s' % (path,)), style, ), ) body = html.body( html.h1('directory listing of %s' % (path,)), ) h.append(body) table = html.table() body.append(table) tbody = html.tbody() table.append(tbody) items = list(path.listdir()) items.sort(key=lambda p: p.basename) items.sort(key=lambda p: not p.check(dir=True)) for fpath in items: tr = html.tr() tbody.append(tr) td1 = html.td(fpath.check(dir=True) and 'D' or 'F', class_='type') tr.append(td1) href = fpath.basename if href_prefix: href = '%s%s' % (href_prefix, href) if fpath.check(dir=True): href += '/' td2 = html.td(html.a(fpath.basename, href=href), class_='name') tr.append(td2) td3 = html.td(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(fpath.mtime())), class_='mtime') tr.append(td3) if fpath.check(dir=True): size = '' unit = '' else: size = fpath.size() unit = 'B' for u in ['kB', 'MB', 'GB', 'TB']: if size > 1024: size = round(size / 1024.0, 2) unit = u td4 = html.td('%s %s' % (size, unit), class_='size') tr.append(td4) return unicode(h)
def append_extra_html(self, extra, extra_index, test_index): href = None if extra.get("format") == extras.FORMAT_IMAGE: self._append_image(extra, extra_index, test_index) elif extra.get("format") == extras.FORMAT_HTML: self.additional_html.append(html.div(raw(extra.get("content")))) elif extra.get("format") == extras.FORMAT_JSON: content = json.dumps(extra.get("content")) if self.self_contained: href = data_uri(content, mime_type=extra.get("mime_type")) else: href = self.create_asset( content, extra_index, test_index, extra.get("extension") ) elif extra.get("format") == extras.FORMAT_TEXT: content = extra.get("content") if isinstance(content, bytes): content = content.decode("utf-8") if self.self_contained: href = data_uri(content) else: href = self.create_asset( content, extra_index, test_index, extra.get("extension") ) elif extra.get("format") == extras.FORMAT_URL: href = extra.get("content") elif extra.get("format") == extras.FORMAT_VIDEO: self._append_video(extra, extra_index, test_index) if href is not None: self.links_html.append( html.a( extra.get("name"), class_=extra.get("format"), href=href, target="_blank", ) ) self.links_html.append(" ")
def findlinks_view(context, request): title = "%s: all package links without root/pypi" % (context.stage.name) projectnames = set() for stage, names in context.stage.op_sro("list_projectnames_perstage"): if stage.ixconfig["type"] == "mirror": continue projectnames.update(names) all_links = [] basenames = set() for projectname in sorted(projectnames): for stage, res in context.stage.op_sro_check_pypi_whitelist( "get_releaselinks_perstage", projectname=projectname): if stage.ixconfig["type"] == "mirror": continue for link in res: if link.eggfragment: key = link.eggfragment else: key = link.basename if key not in basenames: basenames.add(key) all_links.append(link) links = [] for link in sorted(all_links, key=attrgetter('basename')): href = url_for_entrypath(request, link.entrypath) entry = link.entry if entry.eggfragment: href += "#egg=%s" % entry.eggfragment elif entry.md5: href += "#md5=%s" % entry.md5 links.extend([ "/".join(link.entrypath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n"]) if not links: links = [html.p('No releases.')] return Response(html.html( html.head( html.title(title)), html.body( html.h1(title), "\n", links)).unicode(indent=2))
def findlinks_view(context, request): title = "%s: all package links without root/pypi" % (context.stage.name) projects = set() for stage, names in context.stage.op_sro("list_projects_perstage"): if stage.ixconfig["type"] == "mirror": continue projects.update(names) all_links = [] basenames = set() for project in sorted(projects): for stage, res in context.stage.op_sro_check_mirror_whitelist( "get_releaselinks_perstage", project=project): if stage.ixconfig["type"] == "mirror": continue for link in res: if getattr(link, 'eggfragment', None): key = link.eggfragment else: key = link.basename if key not in basenames: basenames.add(key) all_links.append(link) links = [] for link in sorted(all_links, key=attrgetter('basename')): href = url_for_entrypath(request, link.entrypath) entry = link.entry if getattr(entry, 'eggfragment', None): href += "#egg=%s" % entry.eggfragment elif entry.hash_spec: href += "#%s" % entry.hash_spec links.extend([ "/".join(link.entrypath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n" ]) if not links: links = [html.p('No releases.')] return Response( html.html(html.head(html.title(title)), html.body(html.h1(title), "\n", links)).unicode(indent=2))
def _generate_environment(self, config): if not hasattr(config, '_metadata') or config._metadata is None: return [] metadata = config._metadata environment = [html.h2('Environment')] rows = [] keys = [k for k in metadata.keys() if metadata[k]] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, basestring) and value.startswith('http'): value = html.a(value, href=value, target='_blank') elif isinstance(value, (list, tuple, set)): value = ', '.join((str(i) for i in value)) rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id='environment')) return environment
def _generate_environment(self, config): if not hasattr(config, '_metadata') or config._metadata is None: return [] metadata = config._metadata environment = [html.h2('Environment')] rows = [] keys = [k for k in metadata.keys()] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, basestring) and value.startswith('http'): value = html.a(value, href=value, target='_blank') elif isinstance(value, (list, tuple, set)): value = ', '.join((str(i) for i in value)) rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id='environment')) return environment
def test_add_row(self): doc = HTMLDocument('ascii') doc.add_row(1, ['""" this is a foo implementation """']) doc.add_row(2, ['']) doc.add_row(3, ['class ', html.a('Foo', name='Foo'), ':']) doc.add_row(4, [' pass']) tbody = doc.tbody assert len(tbody) == 4 assert unicode(tbody[0][0]) == '<td class="lineno">1</td>' assert unicode(tbody[0][1]) == ('<td class="code">' '<span class="string">' '""" ' 'this is a foo implementation ' '"""' '</span></td>') assert unicode(tbody[1][1]) == '<td class="code"> </td>' assert unicode(tbody[2][1]) == ('<td class="code">' '<span class="alt_keyword">class' '</span> ' '<a name="Foo">Foo</a>:</td>') assert unicode(tbody[3][1]) == ('<td class="code"> ' '<span class="alt_keyword">pass' '</span></td>')
def html_for_module(module): from py.xml import html out = file_for_module(module) ourlink = link_for_module('', module) head = [html.title(module.name)] body = [html.h1(module.name)] body.append(html.p('This module defines these names:')) listbody = [] defuses = {} for d in module.definitions: uses = [] for n in sorted(module.importers): N = module.system.modules[n] if N._imports[module.name].get(d) == True: uses.append(n) if not d.startswith('_'): if uses: listbody.append( html.li(html.a(d, href=link_for_name(ourlink, module, d)))) defuses[d] = uses else: listbody.append(html.li(d)) body.append(html.ul(listbody)) body.append(html.p('This module imports the following:')) listbody1 = [] for n in sorted(module._imports): if n in ('autopath', '__future__'): continue if n in module.system.modules: listbody2 = [ html.a(n, href=link_for_module(ourlink, module.system.modules[n])) ] else: listbody2 = [n] listbody3 = [] for o in sorted(module._imports[n]): if module._imports[n][o] == True: if n in module.system.modules: listbody3.append( html.li( html.a(o, href=link_for_name(ourlink, module.system.modules[n], o)))) else: listbody3.append(html.li(o)) if listbody3: listbody2.append(html.ul(listbody3)) listbody1.append(html.li(listbody2)) body.append(html.ul(listbody1)) body.append(html.p('This module is imported by the following:')) listbody1 = [] for n in module.importers: licontents = [ html.a(n, href=link_for_module(ourlink, module.system.modules[n])) ] contents = [] for o in sorted(module.system.modules[n]._imports[module.name]): contents.append( html.li(html.a(o, href=link_for_name(ourlink, module, o)))) if contents: licontents.append(html.ul(contents)) listbody1.append(html.li(licontents)) body.append(html.ul(listbody1)) out.write(html.html(head, body).unicode()) for d in defuses: out = file_for_name(module, d) ourlink = link_for_name('', module, d) head = [html.title(module.name + '.' + d)] body = [ html.h1([ html.a(module.name, href=link_for_module(ourlink, module)), '.' + d ]) ] contents = [] for n in defuses[d]: N = module.system.modules[n] contents.append( html.li(html.a(n, href=link_for_module(ourlink, N)))) body.append(html.p('This name is used in')) body.append(html.ul(contents)) out.write(html.html(head, body).unicode())
def _appendrow(self, result, report): time = getattr(report, 'duration', 0.0) additional_html = [] links_html = [] for extra in getattr(report, 'extra', []): href = None if extra.get('format') == extras.FORMAT_IMAGE: href = '#' image = 'data:image/png;base64,{0}'.format( extra.get('content')) additional_html.append(html.div( html.a(html.img(src=image), href="#"), class_='image')) elif extra.get('format') == extras.FORMAT_HTML: additional_html.append(html.div(raw(extra.get('content')))) elif extra.get('format') == extras.FORMAT_JSON: href = data_uri(json.dumps(extra.get('content')), mime_type='application/json') elif extra.get('format') == extras.FORMAT_TEXT: href = data_uri(extra.get('content')) elif extra.get('format') == extras.FORMAT_URL: href = extra.get('content') if href is not None: links_html.append(html.a( extra.get('name'), class_=extra.get('format'), href=href, target='_blank')) links_html.append(' ') if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): if not PY3: line = line.decode('utf-8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(escape(line)), class_='error')) else: log.append(raw(escape(line))) log.append(html.br()) for header, content in report.sections: log.append(' {0} '.format(header).center(80, '-')) log.append(html.br()) log.append(content) else: log = html.div(class_='empty log') log.append('No log output captured.') additional_html.append(log) test_id = report.nodeid if report.when != 'call': test_id = '::'.join([report.nodeid, report.when]) self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(test_id, class_='col-name'), html.td('{0:.2f}'.format(time), class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='extra')], class_=result.lower() + ' results-table-row'))
def append_extra_html(self, extra, extra_index, test_index): href = None if extra.get("format") == extras.FORMAT_IMAGE: content = extra.get("content") try: is_uri_or_path = content.startswith( ("file", "http")) or isfile(content) except ValueError: # On Windows, os.path.isfile throws this exception when # passed a b64 encoded image. is_uri_or_path = False if is_uri_or_path: if self.self_contained: warnings.warn("Self-contained HTML report " "includes link to external " "resource: {}".format(content)) html_div = html.a(html.img(src=content), href=content) elif self.self_contained: src = "data:{};base64,{}".format(extra.get("mime_type"), content) html_div = html.img(src=src) else: content = b64decode(content.encode("utf-8")) href = src = self.create_asset(content, extra_index, test_index, extra.get("extension"), "wb") html_div = html.a(html.img(src=src), href=href) self.additional_html.append(html.div(html_div, class_="image")) elif extra.get("format") == extras.FORMAT_HTML: self.additional_html.append(html.div(raw( extra.get("content")))) elif extra.get("format") == extras.FORMAT_JSON: content = json.dumps(extra.get("content")) if self.self_contained: href = data_uri(content, mime_type=extra.get("mime_type")) else: href = self.create_asset(content, extra_index, test_index, extra.get("extension")) elif extra.get("format") == extras.FORMAT_TEXT: content = extra.get("content") if isinstance(content, bytes): content = content.decode("utf-8") if self.self_contained: href = data_uri(content) else: href = self.create_asset(content, extra_index, test_index, extra.get("extension")) elif extra.get("format") == extras.FORMAT_URL: href = extra.get("content") if href is not None: self.links_html.append( html.a( extra.get("name"), class_=extra.get("format"), href=href, target="_blank", )) self.links_html.append(" ")
def _generate_report(self, session): suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time numtests = self.passed + self.failed + self.xpassed + self.xfailed generated = datetime.datetime.now() self.style_css = pkg_resources.resource_string( __name__, os.path.join('resources', 'style.css')) if PY3: self.style_css = self.style_css.decode('utf-8') if ANSI: ansi_css = [ '\n/******************************', ' * ANSI2HTML STYLES', ' ******************************/\n'] ansi_css.extend([str(r) for r in style.get_styles()]) self.style_css += '\n'.join(ansi_css) # <DF> Add user-provided CSS for path in self.config.getoption('css') or []: self.style_css += '\n/******************************' self.style_css += '\n * CUSTOM CSS' self.style_css += '\n * {}'.format(path) self.style_css += '\n ******************************/\n\n' with open(path, 'r') as f: self.style_css += f.read() css_href = '{0}/{1}'.format('assets', 'style.css') html_css = html.link(href=css_href, rel='stylesheet', type='text/css') if self.self_contained: html_css = html.style(raw(self.style_css)) head = html.head( html.meta(charset='utf-8'), html.title('Test Report'), html_css) class Outcome: def __init__(self, outcome, total=0, label=None, test_result=None, class_html=None): self.outcome = outcome self.label = label or outcome self.class_html = class_html or outcome self.total = total self.test_result = test_result or outcome self.generate_checkbox() self.generate_summary_item() def generate_checkbox(self): checkbox_kwargs = {'data-test-result': self.test_result.lower()} if self.total == 0: checkbox_kwargs['disabled'] = 'true' self.checkbox = html.input(type='checkbox', checked='true', onChange='filter_table(this)', name='filter_checkbox', class_='filter', hidden='true', **checkbox_kwargs) def generate_summary_item(self): self.summary_item = html.span('{0} {1}'. format(self.total, self.label), class_=self.class_html) outcomes = [Outcome('passed', self.passed), Outcome('skipped', self.skipped), Outcome('failed', self.failed), Outcome('error', self.errors, label='errors'), Outcome('xfailed', self.xfailed, label='expected failures'), Outcome('xpassed', self.xpassed, label='unexpected passes')] if self.rerun is not None: outcomes.append(Outcome('rerun', self.rerun)) summary = [html.p( '{0} tests ran in {1:.2f} seconds. '.format( numtests, suite_time_delta)), html.p('(Un)check the boxes to filter the results.', class_='filter', hidden='true')] for i, outcome in enumerate(outcomes, start=1): summary.append(outcome.checkbox) summary.append(outcome.summary_item) if i < len(outcomes): summary.append(', ') cells = [ html.th('Result', class_='sortable result initial-sort', col='result'), html.th('Test', class_='sortable', col='name'), html.th('Duration', class_='sortable numeric', col='duration'), html.th('Links')] session.config.hook.pytest_html_results_table_header(cells=cells) results = [html.h2('Results'), html.table([html.thead( html.tr(cells), html.tr([ html.th('No results found. Try to check the filters', colspan=len(cells))], id='not-found-message', hidden='true'), id='results-table-head'), self.test_logs], id='results-table')] main_js = pkg_resources.resource_string( __name__, os.path.join('resources', 'main.js')) if PY3: main_js = main_js.decode('utf-8') body = html.body( html.script(raw(main_js)), html.h1(os.path.basename(session.config.option.htmlpath)), html.p('Report generated on {0} at {1} by'.format( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S')), html.a(' pytest-html', href=__pypi_url__), ' v{0}'.format(__version__)), onLoad='init()') body.extend(self._generate_environment(session.config)) summary_prefix, summary_postfix = [], [] session.config.hook.pytest_html_results_summary( prefix=summary_prefix, summary=summary, postfix=summary_postfix) body.extend([html.h2('Summary')] + summary_prefix + summary + summary_postfix) body.extend(results) doc = html.html(head, body) unicode_doc = u'<!DOCTYPE html>\n{0}'.format(doc.unicode(indent=2)) if PY3: # Fix encoding issues, e.g. with surrogates unicode_doc = unicode_doc.encode('utf-8', errors='xmlcharrefreplace') unicode_doc = unicode_doc.decode('utf-8') return unicode_doc
# IF fl_fail flasg is set add stdout info from log, ELSE -> mark as Passed elif child.tag == 'testcase' and post_child.tag == 'system-out': if fl_fail: result = 'Failed' report_log += post_child.text else: result = 'Passed' report_log = post_child.text # IF skipped-> mark as Skipped elif child.tag == 'testcase' and post_child.tag == 'skipped': result = 'Skipped' report_log = post_child.text ###################################################################################################### # Generate TIMS link in HTML from gathered data links_html = html.a(name, href=path, target='_blank') log = html.div(class_='log') # Paint traceback for line in report_log.splitlines(): separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") #print line if exception: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line)))
def make_result_html(self, data): cls_name = "" tc_name = unicode(data["test"]) tc_time = (data["time"] - self.start_times.pop(data["test"])) / 1000. additional_html = [] debug = data.get("extra", {}) links_html = [] status = data["status"] expected = data.get("expected", status) if status != expected: if status == "PASS": status_name = "UNEXPECTED_" + status else: status_name = "EXPECTED_" + status else: status_name = status self.test_count[status_name] += 1 if status in ['SKIP', 'FAIL', 'ERROR']: if debug.get('screenshot'): screenshot = 'data:image/png;base64,%s' % debug['screenshot'] additional_html.append( html.div(html.a(html.img(src=screenshot), href="#"), class_='screenshot')) for name, content in debug.items(): try: if 'screenshot' in name: href = '#' else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode( content) links_html.append( html.a(name.title(), class_=name, href=href, target='_blank')) links_html.append(' ') except: pass log = html.div(class_='log') for line in debug.get("stdout", "").splitlines(): separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find( "exception") != -1: log.append( html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) self.result_rows.append( html.tr([ html.td(status_name, class_='col-result'), html.td(cls_name, class_='col-class'), html.td(tc_name, class_='col-name'), html.td("%.2f" % tc_time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug') ], class_=status_name.lower() + ' results-table-row'))
def append_extra_html(self, extra, extra_index, test_index): href = None #print() #print('-------append_extra_html----------') #print(extra) if extra.get('format') == extras.FORMAT_IMAGE: content = extra.get('content') try: is_uri_or_path = (content.startswith(('file', 'http')) or isfile(content)) except ValueError: # On Windows, os.path.isfile throws this exception when # passed a b64 encoded image. is_uri_or_path = False if is_uri_or_path: if self.self_contained: warnings.warn('Self-contained HTML report ' 'includes link to external ' 'resource: {}'.format(content)) html_div = html.a(html.img(src=content), href=content) elif self.self_contained: src = 'data:{0};base64,{1}'.format( extra.get('mime_type'), content) html_div = html.img(src=src) #print('extra content len: ',len(content)) else: if PY3: content = b64decode(content.encode('utf-8')) else: content = b64decode(content) href = src = self.create_asset( content, extra_index, test_index, extra.get('extension'), 'wb') html_div = html.a(html.img(src=src), href=href) self.additional_html.append(html.div(html_div, class_='image')) elif extra.get('format') == extras.FORMAT_HTML: self.additional_html.append(html.div( raw(extra.get('content')))) elif extra.get('format') == extras.FORMAT_JSON: content = json.dumps(extra.get('content')) if self.self_contained: href = data_uri(content, mime_type=extra.get('mime_type')) else: href = self.create_asset(content, extra_index, test_index, extra.get('extension')) elif extra.get('format') == extras.FORMAT_TEXT: content = extra.get('content') if isinstance(content, bytes): content = content.decode('utf-8') if self.self_contained: href = data_uri(content) else: href = self.create_asset(content, extra_index, test_index, extra.get('extension')) elif extra.get('format') == extras.FORMAT_URL: href = extra.get('content') if href is not None: self.links_html.append(html.a( extra.get('name'), class_=extra.get('format'), href=href, target='_blank')) self.links_html.append(' ')
def _generate_report(self, session): suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time numtests = self.passed + self.failed + self.xpassed + self.xfailed generated = datetime.datetime.now() class Outcome: def __init__( self, outcome, total=0, label=None, test_result=None, class_html=None ): self.outcome = outcome self.label = label or outcome self.class_html = class_html or outcome self.total = total self.test_result = test_result or outcome self.generate_checkbox() self.generate_summary_item() def generate_checkbox(self): checkbox_kwargs = {"data-test-result": self.test_result.lower()} if self.total == 0: checkbox_kwargs["disabled"] = "true" self.checkbox = html.input( type="checkbox", checked="true", onChange="filter_table(this)", name="filter_checkbox", class_="filter", hidden="true", **checkbox_kwargs, ) def generate_summary_item(self): self.summary_item = html.span( f"{self.total} {self.label}", class_=self.class_html ) outcomes = [ Outcome("passed", self.passed, label="通过"), Outcome("skipped", self.skipped, label="跳过"), Outcome("failed", self.failed, label="失败"), Outcome("error", self.errors, label="故障"), Outcome("xfailed", self.xfailed, label="预期的失败"), Outcome("xpassed", self.xpassed, label="未知的通过"), ] if self.rerun is not None: outcomes.append(Outcome("rerun", self.rerun, label="重跑")) summary = [ html.p( "(取消)勾选复选框, 以便筛选测试结果.", class_="filter", hidden="true", ), ] for i, outcome in enumerate(outcomes, start=1): summary.append(outcome.checkbox) summary.append(outcome.summary_item) if i < len(outcomes): summary.append(", ") cells = [ html.th("测试用例", class_="sortable initial-sort", col="name"), html.th("运行时间", class_="sortable numeric", col="duration"), html.th("运行结果", class_="sortable result", col="result"), html.th("日志资源"), ] session.config.hook.pytest_html_results_table_header(cells=cells) results = [ html.table( [ html.thead( html.tr(cells), html.tr( [ html.th( "无测试结果, 请考虑更换其他测试结果筛选条件.", colspan=len(cells), ) ], id="not-found-message", hidden="true", ), id="results-table-head", ), self.test_logs, ], id="results-table", ), ] session.config.hook.pytest_html_report_title(report=self) self.style_css = pkg_resources.resource_string( __name__, os.path.join("resources", "style.css") ).decode("utf-8") main_js = pkg_resources.resource_string( __name__, os.path.join("resources", "main.js") ).decode("utf-8") if ANSI: ansi_css = [ "\n/******************************", " * ANSI2HTML STYLES", " ******************************/\n", ] ansi_css.extend([str(r) for r in style.get_styles()]) self.style_css += "\n".join(ansi_css) # <DF> Add user-provided CSS for path in self.config.getoption("css"): self.style_css += "\n/******************************" self.style_css += "\n * CUSTOM CSS" self.style_css += f"\n * {path}" self.style_css += "\n ******************************/\n\n" with open(path, "r") as f: self.style_css += f.read() css_href = "assets/style.css" icon_href = "assets/favicon.png" html_icon = html.link(href=icon_href, rel="shortcut icon") html_css = html.link(href=css_href, rel="stylesheet", type="text/css") if self.self_contained: html_css = html.style(raw(self.style_css)) head = html.head( html.meta(charset="utf-8"), html.title(self.title), html_icon, html_css ) body = html.body( html.script(raw(main_js)), onLoad="init()", ) overview = [] if hasattr(self, "tester"): overview.append(html.p(html.strong("测试人员:"), self.tester)) if hasattr(self, "department"): overview.append(html.p(html.strong("测试中心:"), self.department)) overview.append( html.p( html.strong("用例统计:"), f"合计 {numtests} 条用例, ", f"运行时间为: {suite_time_delta:.2f} 秒, ", "生成时间为: {} {}".format( generated.strftime("%Y-%m-%d"), generated.strftime("%H:%M:%S") ), ) ) if hasattr(self, "description"): overview.append(html.p(html.strong("测试描述:"), self.description)) overview_html = html.div(overview, id="overview") body.extend( [ html.h1(self.title), html.h3(html.a(self.company["name"], href=self.company["url"])), overview_html, ] ) body.extend(self._generate_environment(session.config)) summary_prefix, summary_postfix = [], [] session.config.hook.pytest_html_results_summary( prefix=summary_prefix, summary=summary, postfix=summary_postfix ) body.extend([html.h2("测试结果详情")] + summary_prefix + summary + summary_postfix) body.extend(results) # Mail Template MailResult.title = self.title MailResult.count = numtests MailResult.passed = self.passed MailResult.failed = self.failed MailResult.xfailed = self.xfailed MailResult.xpassed = self.xpassed MailResult.errors = self.errors MailResult.skipped = self.skipped doc = html.html(head, body) unicode_doc = "<!DOCTYPE html>\n{}".format(doc.unicode(indent=2)) # Fix encoding issues, e.g. with surrogates unicode_doc = unicode_doc.encode("utf-8", errors="xmlcharrefreplace") return unicode_doc.decode("utf-8")