changeset 856:3ee5abad55ea 0.6.x

0.6dev: Merged [933] from trunk.
author osimons
date Sat, 16 Oct 2010 00:36:42 +0000
parents 84aafcda9c9d
children a08acf72a846
files bitten/report/coverage.py
diffstat 1 files changed, 54 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/report/coverage.py
+++ b/bitten/report/coverage.py
@@ -8,11 +8,13 @@
 # you should have received as part of this distribution. The terms
 # are also available at http://bitten.edgewall.org/wiki/License.
 
+from genshi.builder import tag
 from trac.core import *
 from trac.mimeview.api import IHTMLPreviewAnnotator
 from trac.resource import Resource
+from trac.util.datefmt import to_timestamp
 from trac.web.api import IRequestFilter
-from trac.web.chrome import add_stylesheet, add_ctxtnav
+from trac.web.chrome import add_stylesheet, add_ctxtnav, add_warning
 from bitten.api import IReportChartGenerator, IReportSummarizer
 from bitten.model import BuildConfig, Build, Report
 
@@ -139,10 +141,13 @@
     >>> from genshi.builder import tag
     >>> from trac.test import Mock, MockPerm
     >>> from trac.mimeview import Context
+    >>> from trac.util.datefmt import to_datetime, utc
     >>> from trac.web.href import Href
     >>> from bitten.model import BuildConfig, Build, Report
     >>> from bitten.report.tests.coverage import env_stub_with_tables
     >>> env = env_stub_with_tables()
+    >>> repos = Mock(get_changeset=lambda x: Mock(date=to_datetime(12345, utc)))
+    >>> env.get_repository = lambda: repos
 
     >>> BuildConfig(env, name='trunk', path='trunk').insert()
     >>> Build(env, rev=123, config='trunk', rev_time=12345, platform=1).insert()
@@ -151,7 +156,8 @@
     >>> rpt.insert()
 
     >>> ann = TestCoverageAnnotator(env)
-    >>> req = Mock(href=Href('/'), perm=MockPerm(), chrome={}, args={})
+    >>> req = Mock(href=Href('/'), perm=MockPerm(),
+    ...                 chrome={'warnings': []}, args={})
 
     Version in the branch should not match:
     >>> context = Context.from_request(req, 'source', '/branches/blah/foo.py', 123)
@@ -190,11 +196,13 @@
         if resource and isinstance(resource, Resource) \
                     and resource.realm=='source' and data.get('file') \
                     and not req.args.get('annotate', '') == 'coverage':
-            add_ctxtnav(req, 'Coverage',
+            add_ctxtnav(req, tag.a('Coverage',
                     title='Annotate file with test coverage '
                           'data (if available)',
                     href=req.href.browser(resource.id, 
-                        annotate='coverage', rev=resource.version))
+                        annotate='coverage', rev=req.args.get('rev'),
+                        created=data.get('rev')),
+                    rel='nofollow'))
         return template, data, content_type
 
     # IHTMLPreviewAnnotator methods
@@ -209,35 +217,49 @@
 
         # attempt to use the version passed in with the request,
         # otherwise fall back to the latest version of this file.
-        try:
-            version = context.req.args['rev']
-        except KeyError:
-            version = resource.version
-
-        builds = Build.select(self.env, rev=version)
-
-        self.log.debug("Looking for coverage report for %s@%s [%s]..." % (
-                        resource.id, str(resource.version), version))
+        version = context.req.args.get('rev', resource.version)
+        # get the last change revision for the file so that we can
+        # pick coverage data as latest(version >= file_revision)
+        created = context.req.args.get('created', resource.version)
 
-        reports = []
-        for build in builds:
-            config = BuildConfig.fetch(self.env, build.config)
-            # Normalize paths and check (Trac version inconsistencies)
-            if not resource.id.lstrip('/').startswith(config.path.lstrip('/')):
-                continue
-            reports = Report.select(self.env, build=build.id,
-                                    category='coverage')
-            path_in_config = resource.id[len(config.path)+1:].lstrip('/')
-            for report in reports:
-                for item in report.items:
-                    if item.get('file') == path_in_config:
-                        coverage = item.get('line_hits', '').split()
-                        if coverage:
-                            # Return first result with line data
-                            self.log.debug(
-                                "Coverage annotate for %s@%s: %s" % \
-                                (resource.id, resource.version, coverage))
-                            return coverage
+        repos = self.env.get_repository()        
+        version_time = to_timestamp(repos.get_changeset(version).date)
+        if version != created:
+            created_time = to_timestamp(repos.get_changeset(created).date)
+        else:
+            created_time = version_time
+
+        self.log.debug("Looking for coverage report for %s@%s [%s:%s]..." % (
+                        resource.id, str(resource.version), created, version))
+
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute("""
+                SELECT b.id, b.rev, i2.value
+                FROM bitten_config AS c
+                    INNER JOIN bitten_build AS b ON c.name=b.config
+                    INNER JOIN bitten_report AS r ON b.id=r.build
+                    INNER JOIN bitten_report_item AS i1 ON r.id=i1.report
+                    INNER JOIN bitten_report_item AS i2 ON (i1.item=i2.item
+                                                    AND i1.report=i2.report)
+                WHERE i2.name='line_hits'
+                    AND b.rev_time>=%s
+                    AND b.rev_time<=%s
+                    AND i1.name='file'
+                    AND """ + db.concat('c.path', "'/'", 'i1.value') + """=%s
+                ORDER BY b.rev_time DESC LIMIT 1""" ,
+            (created_time, version_time, resource.id.lstrip('/')))
+
+        row = cursor.fetchone()
+        if row:
+            build_id, build_rev, line_hits = row
+            coverage = line_hits.split()
+            self.log.debug("Coverage annotate for %s@%s using build %d: %s",
+                            resource.id, build_rev, build_id, coverage)
+            return coverage
+        add_warning(context.req, "No coverage annotation found for "
+                                 "/%s for revision range [%s:%s]." % (
+                                 resource.id.lstrip('/'), version, created))
         return []
 
     def annotate_row(self, context, row, lineno, line, data):
Copyright (C) 2012-2017 Edgewall Software