author David Douard <>
Fri, 14 Nov 2014 12:51:47 +0100
changeset 1740 f3137466457a
parent 1568 296942d2ed2a
child 1616 dfdb7c972b40
permissions -rw-r--r--
Big Refactoring (BR) of the test execution model Get rid of narval preprocessors in favor of Recipes - Each preprocessing recipe must be run from the "main" recipe (thus we add a ATest.exec_recipe() method that can be called from Recipe execution). - We add a (Repository, checkout_recipe, Recipe) relation, which is the Recipe that tells how to retrieve the code for a given Repository - Also add a (ProjectEnvironment, setup_recipe, Recip) dedicated to perform the installation for a project (compile and install) - Add implementations for these recipes for Python project - Rewrite the quick recipe using this new model

"""this module contains some synthetics report views for test execution results

:organization: Logilab
:copyright: 2009-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: --
:license: General Public License version 2 -
__docformat__ = "restructuredtext en"
_ = unicode

from logilab.common.ureports import HTMLWriter, Table, Span, Link, Text
from logilab.common.decorators import cached
from logilab.mtconverter import xml_escape

from io import StringIO

from cubicweb.uilib import domid
from cubicweb.view import EntityView
from cubicweb.predicates import is_instance

from cubes.narval.views import no_robot_index

def all_check_results(tconfig):
    rset = tconfig._cw.execute('Any MAX(X), XN GROUPBY XN, EXB ORDERBY XN '
                               'WHERE X is CheckResult, X name XN, '
                               'X during_execution EX, EX using_config C, '
                               'EX branch EXB, C eid %(c)s',
                               {'c': tconfig.eid})
    return list(rset.entities())

def latest_check_result_by_name(tconfig, name, branch):
    for cr in all_check_results(tconfig):
        if == name and cr.execution.branch == branch:
            return cr

class ProjectEnvironmentLatestExecutionSummary(EntityView):
    __regid__ = 'summary'
    __select__ = is_instance('ProjectEnvironment')
    title = _('Test executions summary')

    html_headers = no_robot_index

    def call(self, title=None):
        configs = []
        map(configs.extend, (e.reverse_use_environment for e in self.cw_rset.entities()))
        self.multiple_configs_report(configs, title, incontext=True)

    def cell_call(self, row, col, title=None):
        entity = self.cw_rset.get_entity(row, col)
                                     title, incontext=True)

    def multiple_configs_report(self, configs, title, incontext):
        self.w(u'<div class="section">')
        self.w(u'<h3>%s</h3>\n' % (title or self._cw._(self.title)))
        if not configs:
            self.w(self._cw._('no test execution results to display'))
            self.w(multiple_configs_table(self._cw._, configs,

class TestConfigLatestExecutionSummary(ProjectEnvironmentLatestExecutionSummary):
    __select__ = is_instance('TestConfig',)

    html_headers = no_robot_index

    def call(self, title=None):
                                     title, incontext=False)

    def cell_call(self, row, col, title=None):
        self.multiple_configs_report([self.cw_rset.get_entity(row, col)],
                                      title, incontext=False)

class TestExecutionSummary(EntityView):
    __select__ = is_instance('TestExecution',)
    __regid__ = 'summary'

    html_headers = no_robot_index

    def cell_call(self, row, col):
        entity = self.cw_rset.get_entity(row, col)
        self.w(u'<table class="summary">')
               % (self._cw._('name'), self._cw._('status')))
        for checkname in entity.configuration.all_checks():
            check = entity.check_result_by_name(checkname)
            if check is None:
                status = 'nc'
                url = entity.absolute_url()
                status = entity.check_result_by_name(checkname).status
                url = check.absolute_url()
            self.w(u'<tr><td><a href="%s">%s</a></td><td class="status_%s">%s</td></tr>'
                   % (url, xml_escape(checkname), status, status))

def multiple_configs_table(_, configs, incontext=False):
    """return a synthetic reports table for multiple configurations executions
    branches = {}
    allchecks = set()
    for conf in configs:
        for cr in all_check_results(conf):
            branches.setdefault(conf, set()).add(cr.execution.branch)
    allchecks = sorted(allchecks)
    table = Table(cols=2+len(allchecks), klass='apycotreport',
                  cheaders=2, rheaders=1, rrheaders=len(configs) > 5)
    # headers
    for check_name in allchecks:
        table.append(Text(check_name.replace('_', ' ')))
    # table content
    for conf in configs:
        first_branch = True
        if incontext:
            conf_title = conf.printable_value('name')
            conf_title = xml_escape(conf.dc_title())
        for branch in sorted(branches.get(conf, ())):
            if first_branch:
                link = Link(xml_escape(conf.absolute_url()),
                            '%s' % (conf_title,),
                table.append(Span((link,), klass='apycot_testname'))
                table.append(Span(u' '))
            first_branch = False
            link = Link(xml_escape(conf.absolute_url()),
                        '%s' % (xml_escape(branch or 'default'),),
            table.append(Span((link,), klass='apycot_branchname'))
            for column in allchecks:
                checkresult = latest_check_result_by_name(conf, column, branch)
                if checkresult:
                    status = checkresult.status
                    url = checkresult.execution.absolute_url(tab=column)
                    title = Link(xml_escape(url), _(status), klass='apycot_title')
                    title = _('nc')
                    status = 'nc'
                table.append(Span((title,), klass='status_%s' % status))
    # recall table headers
    if len(configs) > 5:
        for check_name in allchecks:
            table.append(Text(check_name.replace('_', ' ')))
    # dump html and return results
    stream = StringIO()
    writer = HTMLWriter(snippet=True)
    writer.format(table, stream, 'unicode')
    return stream.getvalue()