Commit 7aa3ee0a authored by Denis Bilenko's avatar Denis Bilenko

update generate_report.py regarding changes to the test results db

- create columns based libevent version/method/python version/changeset
parent 09599765
...@@ -22,50 +22,97 @@ ...@@ -22,50 +22,97 @@
import sys import sys
import os import os
import sqlite3 import traceback
import glob try:
import sqlite3
except ImportError:
import pysqlite2.dbapi2 as sqlite3
from pprint import pprint
REPO_URL = 'http://bitbucket.org/denis/gevent' REPO_URL = 'http://bitbucket.org/denis/gevent'
row_def = ['testname']
column_def = ['python', 'changeset', 'libevent_version', 'libevent_method']
hubs_order = ['poll', 'selects', 'libevent', 'libev', 'twistedr/selectreactor', 'twistedr/pollreactor', 'twistedr/epollreactor'] CSS = """
a.x
{
color: black;
text-decoration: none;
}
def make_table(database): a.x:hover
{
text-decoration: underline;
}
td.nodata
{
align: center;
bgcolor: gray;
}
table
{
border: 1;
}
th
{
font-weight: normal;
}
th.row
{
text-align: left;
}
"""
def make_table(database, row, column):
c = sqlite3.connect(database) c = sqlite3.connect(database)
res = c.execute(('select command_record.id, testname, hub, runs, errors, fails, ' res = c.execute(('select * from parsed_command_record join command_record on parsed_command_record.id=command_record.id '))
'timeouts, exitcode, stdout from parsed_command_record join ' columns = [x[0].lower() for x in res.description]
'command_record on parsed_command_record.id=command_record.id ')).fetchall() table = {}
table = {} # testname -> hub -> test_result (runs, errors, fails, timeouts) row_set = set()
tests = set() column_set = set()
for id, testname, hub, runs, errors, fails, timeouts, exitcode, stdout in res: VARIES = object()
tests.add(testname) common_fields = {}
test_result = TestResult(runs, errors, fails, timeouts, exitcode, id, stdout) for values in res.fetchall():
table.setdefault(testname, {})[hub] = test_result d = dict(zip(columns, values))
return table, sorted(tests) for k, v in d.items():
def calc_hub_stats(table):
hub_stats = {} # hub -> cumulative test_result
for testname in table:
for hub in table[testname]:
test_result = table[testname][hub]
hub_stats.setdefault(hub, TestResult(0,0,0,0)).__iadd__(test_result)
hubs = hub_stats.items()
hub_names = sorted(hub_stats.keys())
def get_order(hub):
try: try:
return hubs_order.index(hub) current_value = common_fields[k]
except ValueError: except KeyError:
return 100 + hub_names.index(hub) common_fields[k] = v
hubs.sort(key=lambda (hub, stats): get_order(hub)) else:
return hub_stats, [x[0] for x in hubs] if current_value != v:
common_fields[k] = VARIES
row_params = tuple(d[k] for k in row)
column_params = tuple(d[k] for k in column)
test_result = TestResult(**d)
row_set.add(row_params)
column_set.add(column_params)
table.setdefault(row_params, {})[column_params] = test_result
# columns totals
table.setdefault(None, {}).setdefault(column_params, TestResult(0, 0, 0, 0)).__iadd__(test_result)
# row totals
table.setdefault(row_params, {}).setdefault(None, TestResult(0, 0, 0, 0)).__iadd__(test_result)
common_fields = dict((k, v) for (k, v) in common_fields.items() if v is not VARIES)
return table, sorted(row_set), sorted(column_set), common_fields
class TestResult: class TestResult:
def __init__(self, runs, errors, fails, timeouts, exitcode=None, id=None, output=None): def __init__(self, runs, errors, fails, timeouts, exitcode=None, id=None, output=None, **ignore_kwargs):
self.runs = max(runs, 0) self.runs = max(int(runs), 0)
self.errors = max(errors, 0) self.errors = max(int(errors), 0)
self.fails = max(fails, 0) self.fails = max(int(fails), 0)
self.timeouts = max(timeouts, 0) self.timeouts = max(int(timeouts), 0)
self.exitcode = exitcode self.exitcode = int(exitcode) if exitcode is not None else None
self.id = id self.id = id
self.output = output self.output = output
...@@ -142,7 +189,7 @@ class TestResult: ...@@ -142,7 +189,7 @@ class TestResult:
r += '\n' + '\n'.join(self.warnings()).replace(' ', ' ') r += '\n' + '\n'.join(self.warnings()).replace(' ', ' ')
return r return r
def format(self): def __str__(self):
text = self.text().replace('\n', '<br>\n') text = self.text().replace('\n', '<br>\n')
if self.id is None: if self.id is None:
valign = 'bottom' valign = 'bottom'
...@@ -151,50 +198,83 @@ class TestResult: ...@@ -151,50 +198,83 @@ class TestResult:
valign = 'center' valign = 'center'
return '<td align=center valign=%s bgcolor=%s>%s</td>' % (valign, self.color(), text) return '<td align=center valign=%s bgcolor=%s>%s</td>' % (valign, self.color(), text)
def format_testname(changeset, test): def decorate_testname(testname, common_fields):
return '<a href="%s/src/%s/greentest/%s">%s</a>' % (REPO_URL, changeset, test, test) return '<a href="%s/src/%s/greentest/%s">%s</a>' % (REPO_URL, common_fields['changeset'].rstrip('+').split('_')[1], testname, testname)
def format_table(table, hubs, tests, hub_stats, changeset): def decorate(field_name, field_value, common_fields):
r = '<table border=1>\n<tr>\n<td/>\n' d = globals().get('decorate_%s' % field_name)
for hub in hubs: if d is not None:
r += '<td align=center>%s</td>\n' % hub try:
r += '</tr>\n' return d(field_value, common_fields)
except KeyError:
pass
except Exception:
traceback.print_exc()
return field_value
r += '<tr><td>Total</td>'
for hub in hubs: def format_table(table, row_def, rows, column_def, columns, common_fields):
test_result = hub_stats.get(hub) r = '<table border=1>\n'
if test_result is None: for index, header_row in enumerate(column_def):
r += '<td align=center bgcolor=gray>no data</td>' r += '<tr>\n'
r += '<th/>' * len(row_def)
for column in columns:
if column_def[index] not in common_fields:
r += '<th>%s</th>\n' % column[index]
r += '</tr>\n'
for row in [None, ] + rows:
r += '<tr>\n'
if row is None:
r += '<th class=row colspan=%s>Total</th>' % len(row_def)
else: else:
r += test_result.format() + '\n' for row_def_item, row_item in zip(row_def, row):
r += '</tr>' row_item = decorate(row_def_item, row_item, common_fields)
r += '<th class=row>%s</th>\n' % row_item
for column in columns:
try:
r += '%s\n' % table[row][column]
except KeyError:
r += '<td align=center bgcolor=gray>no data</td>'
r += '</tr>\n'
r += '</table>\n'
return r
r += '<tr><td colspan=%s/></tr>' % (len(hubs)+1)
for test in tests: def decorate_changeset(changeset):
r += '<tr><td>%s</td>' % format_testname(changeset, test) rev, hash = changeset.split('_')
for hub in hubs: text = 'gevent changeset %s: %s</a>' % (rev, hash)
test_result = table[test].get(hub) url = '%s/changeset/%s' % (REPO_URL, hash.rstrip('+'))
if test_result is None: text = '<a href="%s">%s</a>' % (url, text.replace('+', '<b>+</b>'))
r += '<td align=center bgcolor=gray>no data</td>' return text
else:
r += test_result.format() + '\n' def decorate_python(python):
r += '</tr>' return 'Python version: %s' % python
r += '</table>'
return r
def format_header(rev, changeset, pyversion): def format_header_common_fields(fields):
result = '<table width=99%%><tr><td>' result = ''
url = '%s/changeset/%s' % (REPO_URL, changeset) changeset = fields.get('changeset', None)
result += '<a href="%s">gevent changeset %s: %s</a>' % (url, rev, changeset) if changeset is not None:
result += '</td><tr><tr><td>Python version: %s</td><tr></table><p>' % pyversion result += decorate_changeset(changeset) + '<br>\n'
python = fields.get('python', None)
if python is not None:
result += decorate_python(python) + '<br><br>\n'
return result, ['changeset', 'python']
def format_footer_common_fields(fields):
result = '<table class=common border=1>\n'
for k, v in sorted(fields.items()):
result += '<tr><th>%s</th><td>%s</td></tr>\n' % (k, v)
result += '</table>'
return result return result
def format_html(table, rev, changeset, pyversion): def format_html(table, common_fields):
r = '<html><head><style type="text/css">a.x {color: black; text-decoration: none;} a.x:hover {text-decoration: underline;} </style></head><body>' r = '<html><head><style type="text/css">%s</style></head><body>' % CSS
r += format_header(rev, changeset, pyversion) x, ignore = format_header_common_fields(common_fields)
r += x
r += table r += table
r += '<br><br>'
r += format_footer_common_fields(dict((k, v) for (k, v) in common_fields.items() if k not in ignore))
r += '</body></html>' r += '</body></html>'
return r return r
...@@ -207,25 +287,31 @@ def generate_raw_results(path, database): ...@@ -207,25 +287,31 @@ def generate_raw_results(path, database):
sys.stderr.write('\n') sys.stderr.write('\n')
def main(db): def main(db):
full_changeset = '.'.join(db.split('.')[1:-1]) table, rows, columns, common_fields = make_table(db, row=row_def, column=column_def)
rev, changeset, pyversion = full_changeset.split('_') if common_fields:
table, tests = make_table(db) pprint(common_fields)
hub_stats, hubs = calc_hub_stats(table) for field in ['runs', 'errors', 'fails', 'timeouts', 'exitcode', 'id', 'output']:
report = format_html(format_table(table, hubs, tests, hub_stats, changeset), rev, changeset, pyversion) common_fields.pop(field, None)
path = '../htmlreports/%s' % full_changeset
table = format_table(table, row_def, rows, column_def, columns, common_fields)
report = format_html(table, common_fields)
path = '../testresults/'
try: try:
os.makedirs(path) os.makedirs(path)
except OSError, ex: except OSError, ex:
if 'File exists' not in str(ex): if 'File exists' not in str(ex):
raise raise
file(path + '/index.html', 'w').write(report) file_path = os.path.join(path, 'index.html')
file(file_path, 'w').write(report)
print '%s: written %s' % (db, file_path)
generate_raw_results(path, db) generate_raw_results(path, db)
if __name__=='__main__': if __name__=='__main__':
if not sys.argv[1:]: if not sys.argv[1:]:
latest_db = sorted(glob.glob('results.*.db'), key=lambda f: os.stat(f).st_mtime)[-1] from greentest.record_results import get_results_db
print latest_db db = get_results_db()
sys.argv.append(latest_db) sys.argv.append(db)
for db in sys.argv[1:]: for db in sys.argv[1:]:
main(db) main(db)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment