[pypy-svn] r58178 - in pypy/build/bot2/pypybuildbot: . test
pedronis at codespeak.net
pedronis at codespeak.net
Tue Sep 16 16:14:23 CEST 2008
Author: pedronis
Date: Tue Sep 16 16:14:21 2008
New Revision: 58178
Modified:
pypy/build/bot2/pypybuildbot/summary.py
pypy/build/bot2/pypybuildbot/test/test_summary.py
Log:
(iko, pedronis)
basic summary with links to tracebacks is now working
Modified: pypy/build/bot2/pypybuildbot/summary.py
==============================================================================
--- pypy/build/bot2/pypybuildbot/summary.py (original)
+++ pypy/build/bot2/pypybuildbot/summary.py Tue Sep 16 16:14:21 2008
@@ -1,22 +1,29 @@
+import urllib
+
import py
html = py.xml.html
from buildbot.status.web.base import HtmlResource
-# xxx caching?
class RevisionOutcomeSet(object):
- def __init__(self, rev):
+ def __init__(self, rev, key=None):
self.revision = rev
+ self.key = key
self._outcomes = {}
self.failed = set()
self.skipped = set()
- # xxx failure tracebacks
+ self.longreprs = {}
- def populate_one(self, name, shortrepr):
- namekey = name.split(':', 1) # xxx not always the correct thing
- if namekey[0].endswith('.py'):
- namekey[0] = namekey[0][:-3].replace('/', '.')
+ def populate_one(self, name, shortrepr, longrepr=None):
+ if shortrepr == '!':
+ namekey = [name, '']
+ else:
+ namekey = name.split(':', 1)
+ if namekey[0].endswith('.py'):
+ namekey[0] = namekey[0][:-3].replace('/', '.')
+ if len(namekey) == 1:
+ namekey.append('')
namekey = tuple(namekey)
self._outcomes[namekey] = shortrepr
@@ -27,17 +34,80 @@
else:
self.failed.add(namekey)
+ if longrepr:
+ self.longreprs[namekey] = longrepr
+
def populate(self, log):
+ kind = None
+ def add_one():
+ if kind is not None:
+ self.populate_one(name, kind, ''.join(longrepr))
for line in log.readlines():
- kind = line[0]
- if kind == ' ':
+ first = line[0]
+ if first == ' ':
+ longrepr.append(line[1:])
continue
+ add_one()
+ kind = first
name = line[2:].rstrip()
- self.populate_one(name, kind)
+ longrepr = []
+ add_one()
def get_outcome(self, namekey):
return self._outcomes[namekey]
+ def get_key_namekey(self, namekey):
+ return (self.key, namekey)
+
+ def get_longrepr(self, namekey):
+ return self.longreprs.get(namekey, '')
+
+class RevisionOutcomeSetCache(object):
+ CACHESIZE = 10
+
+ def __init__(self):
+ self._outcome_sets = {}
+ self._lru = []
+
+ def _load_outcome_set(self, status, key):
+ builderName, buildNumber = key
+ builderStatus = status.getBuilder(builderName)
+ build = builderStatus.getBuild(buildNumber)
+
+ rev = int(build.getProperty("got_revision"))
+ log = None
+ for step in build.getSteps():
+ candLogs = [log for log in step.getLogs()
+ if log.getName() == "pytestLog"]
+ if candLogs:
+ log = candLogs[0]
+ break
+
+ outcome_set = RevisionOutcomeSet(rev, key)
+ if log is None or not log.hasContents():
+ outcome_set.populate_one('<run>', '!', "no log from the test run")
+ else:
+ outcome_set.populate(log)
+ return outcome_set
+
+ def get(self, status, key):
+ try:
+ self._lru.remove(key)
+ except ValueError:
+ pass
+ self._lru.append(key)
+ try:
+ return self._outcome_sets[key]
+ except KeyError:
+ pass
+ if len(self._lru) > self.CACHESIZE:
+ dead_key = self._lru.pop(0)
+ self._outcome_sets.pop(dead_key, None)
+ outcome_set = self._load_outcome_set(status, key)
+ self._outcome_sets[key] = outcome_set
+ return outcome_set
+
+outcome_set_cache = RevisionOutcomeSetCache()
class GatherOutcomeSet(object):
@@ -47,7 +117,6 @@
self._skipped = None
self.revision = map.values()[0].revision
-
@property
def failed(self):
if self._failed is None:
@@ -68,6 +137,12 @@
def get_outcome(self, namekey):
return self.map[namekey[0]].get_outcome(namekey[1:])
+
+ def get_key_namekey(self, namekey):
+ return self.map[namekey[0]].get_key_namekey(namekey[1:])
+
+ def get_longrepr(self, namekey):
+ return self.map[namekey[0]].get_longrepr(namekey[1:])
# ________________________________________________________________
@@ -88,6 +163,17 @@
def __init__(self):
self.sections = []
+ def make_longrepr_url_for(self, outcome_set, namekey):
+ cachekey, namekey = outcome_set.get_key_namekey(namekey)
+ parms={
+ 'builder': cachekey[0],
+ 'build': cachekey[1],
+ 'mod': namekey[0],
+ 'testname': namekey[1]
+ }
+ qs = urllib.urlencode(parms)
+ return "/summary/longrepr?" + qs
+
def add_section(self, outcome_sets):
by_rev = sorted((outcome_set.revision, outcome_set) for outcome_set
in outcome_sets)
@@ -97,9 +183,9 @@
for rev, outcome_set in by_rev:
count_failures = len(outcome_set.failed)
count_skipped = len(outcome_set.skipped)
- lines.append("%s %d" % (bars(),rev))
- lines.append(bars())
-
+ lines.append(["%s %d" % (bars(),rev), "\n"])
+ lines.append([bars(), "\n"])
+
failed = set()
for rev, outcome_set in by_rev:
failed.update(outcome_set.failed)
@@ -110,20 +196,72 @@
line = []
for rev, outcome_set in by_rev:
letter = outcome_set.get_outcome(failure)
- line.append(" %s" % letter)
+ if outcome_set.get_longrepr(failure):
+ longrepr_url = self.make_longrepr_url_for(outcome_set,
+ failure)
+ line.append([" ",html.a(letter, href=longrepr_url)])
+ else:
+ line.append(" %s" % letter)
for width, key in zip(colwidths, failure):
line.append(" %-*s" % (width, key))
- lines.append(''.join(line))
+ lines.append(line)
+ lines.append("\n")
- section = html.pre('\n'.join(lines))
+ section = html.pre(lines)
self.sections.append(section)
def render(self):
body_html = html.div(self.sections)
return body_html.unicode()
+class LongRepr(HtmlResource):
+
+ def get_namekey(self, request):
+ mod = request.args.get('mod', [])
+ if not mod:
+ mod = None
+ else:
+ mod = mod[0]
+
+ testname = request.args.get('testname', [])
+ if testname:
+ testname = testname[0]
+ else:
+ testname = ''
+
+ return (mod, testname)
+
+ def getTitle(self, request):
+ mod, testname = self.get_namekey(request)
+ if mod is None:
+ return "no such test"
+ return "%s %s" % (mod, testname)
+
+ def body(self, request):
+ builder = request.args.get('builder', [])
+ build = request.args.get('build', [])
+ if not builder or not build:
+ return "no such build"
+ builderName = builder[0]
+ buildNumber = int(build[0])
+
+ outcome_set = outcome_set_cache.get(self.getStatus(request),
+ (builderName,
+ buildNumber))
+
+ namekey = self.get_namekey(request)
+
+ longrepr = outcome_set.get_longrepr(namekey)
+
+ return html.pre(longrepr).unicode()
+
class Summary(HtmlResource):
+ title="Summary" # xxx
+
+ def __init__(self):
+ HtmlResource.__init__(self)
+ self.putChild('longrepr', LongRepr())
def recentRevisions(self, request):
# xxx branches
@@ -135,13 +273,10 @@
rev = int(build.getProperty("got_revision"))
revBuilds = revs.setdefault(rev, {})
if builderName not in revBuilds: # pick the most recent or ?
- # xxx hack, go through the steps and make sure
- # the log is there
- log = [log for log in build.getLogs()
- if log.getName() == "pytestLog"][0]
- outcome_set = RevisionOutcomeSet(rev)
- outcome_set.populate(log)
+ key = (builderName, build.getNumber())
+ outcome_set = outcome_set_cache.get(status, key)
revBuilds[builderName] = outcome_set
+
return revs
def body(self, request):
Modified: pypy/build/bot2/pypybuildbot/test/test_summary.py
==============================================================================
--- pypy/build/bot2/pypybuildbot/test/test_summary.py (original)
+++ pypy/build/bot2/pypybuildbot/test/test_summary.py Tue Sep 16 16:14:21 2008
@@ -4,9 +4,10 @@
class TestOutcomes(object):
def test_populate(self):
- rev_outcome_set = summary.RevisionOutcomeSet(50000)
+ rev_outcome_set = summary.RevisionOutcomeSet(50000, ('foo', 40))
assert rev_outcome_set.revision == 50000
+ assert rev_outcome_set.key == ('foo', 40)
log = StringIO("""F a/b.py:test_one
. a/b.py:test_two
@@ -20,24 +21,119 @@
res = rev_outcome_set.get_outcome(("a.b", "test_one"))
assert res == 'F'
+ key_namekey = rev_outcome_set.get_key_namekey(("a.b", "test_one"))
+ assert key_namekey == (('foo', 40), ("a.b", "test_one"))
res = rev_outcome_set.get_outcome(("a.b", "test_three"))
assert res == 's'
+ key_namekey = rev_outcome_set.get_key_namekey(("a.b", "test_three"))
+ assert key_namekey == (('foo', 40), ("a.b", "test_three"))
res = rev_outcome_set.get_outcome(("a.b", "test_two"))
assert res == '.'
+ def test_populate_from_empty(self):
+ rev_outcome_set = summary.RevisionOutcomeSet(0)
+ log = StringIO("")
+ rev_outcome_set.populate(log)
+
+ def test_populate_longrepr(self):
+ rev_outcome_set = summary.RevisionOutcomeSet(50000)
+ log = StringIO("""F a/b.py:test_one
+ some
+ traceback
+. a/b.py:test_two
+s a/b.py:test_three
+ some skip
+""")
+
+ rev_outcome_set.populate(log)
+
+ assert len(rev_outcome_set.skipped) == 1
+ assert len(rev_outcome_set.failed) == 1
+
+ assert rev_outcome_set.longreprs == {
+("a.b","test_three"): "some skip\n",
+("a.b", "test_one"): "some\ntraceback\n"
+ }
+
+ res = rev_outcome_set.get_longrepr(("a.b", "test_two"))
+ assert res == ''
+
+ res = rev_outcome_set.get_longrepr(("a.b", "test_one"))
+ assert res == "some\ntraceback\n"
+
+ def test_populate_special(self):
+ rev_outcome_set = summary.RevisionOutcomeSet(50000)
+ log = StringIO("""F a/b.py
+s a/c.py
+! <run>
+! /a/b/c.py:92
+""")
+
+ rev_outcome_set.populate(log)
+
+ assert rev_outcome_set.failed == set([
+ ("a.b", ''),
+ ("<run>", ''),
+ ("/a/b/c.py:92", '')])
+
+ assert rev_outcome_set.skipped == set([
+ ("a.c", '')])
+
+
+ def test_RevisionOutcomeSetCache(self):
+ cache = summary.RevisionOutcomeSetCache()
+ cache.CACHESIZE = 3
+ calls = []
+ def load(x, y):
+ calls.append(y)
+ return y
+
+ cache._load_outcome_set = load
+
+ res = cache.get('status', 'a')
+ assert res == 'a'
+ cache.get('status', 'b')
+ cache.get('status', 'c')
+
+ assert calls == ['a', 'b', 'c']
+
+ cache.get('status', 'a')
+ cache.get('status', 'b')
+ res = cache.get('status', 'c')
+ assert res == 'c'
+
+ assert calls == ['a', 'b', 'c']
+
+ calls = []
+ res = cache.get('status', 'd')
+ assert res == 'd'
+ assert cache.get('status', 'c') == 'c'
+ assert cache.get('status', 'b') == 'b'
+ assert calls == ['d']
+
+ res = cache.get('status', 'a')
+ assert res == 'a'
+
+ assert calls == ['d', 'a']
+
def test_GatherOutcomeSet(self):
- rev_outcome_set_foo = summary.RevisionOutcomeSet(50000)
+ key_foo = ('foo', 3)
+ rev_outcome_set_foo = summary.RevisionOutcomeSet(50000, key_foo)
log = StringIO("""F a/b.py:test_one
+ some
+ traceback
. a/b.py:test_two
s a/b.py:test_three
""")
rev_outcome_set_foo.populate(log)
-
- rev_outcome_set_bar = summary.RevisionOutcomeSet(50000)
+
+ key_bar = ('bar', 7)
+ rev_outcome_set_bar = summary.RevisionOutcomeSet(50000,
+ key_bar)
log = StringIO(""". a/b.py:test_one
. a/b.py:test_two
s a/b.py:test_three
@@ -70,6 +166,13 @@
outcome2 = goutcome.get_outcome((prefix, mod, testname))
assert outcome2 == outcome1
+ key_namekey1 = d[prefix].get_key_namekey((mod, testname))
+ key_namekey2 = goutcome.get_key_namekey((prefix, mod,
+ testname))
+ assert key_namekey1 == key_namekey2
+
+
+
goutcome_top = summary.GatherOutcomeSet({'sub': goutcome})
assert goutcome_top.failed == set([('sub', 'foo', 'a.b', 'test_one')])
@@ -77,6 +180,12 @@
res = goutcome_top.get_outcome(('sub', 'foo', 'a.b', 'test_one'))
assert res == 'F'
+ res = goutcome_top.get_key_namekey(('sub', 'foo', 'a.b', 'test_one'))
+ assert res == (key_foo, ('a.b', 'test_one'))
+
+ res = goutcome_top.get_longrepr(('sub', 'foo', 'a.b', 'test_one'))
+ assert res == "some\ntraceback\n"
+
def test_colsizes(self):
failed = [('a', 'abc', 'd'), ('ab', 'c', 'xy'),
('ab', '', 'cd')]
More information about the Pypy-commit
mailing list