[visualisation] graph of time taken by tests in "test reports" tabs (closes #2176598)
authorArthur Lutz <arthur.lutz@logilab.fr>
Mon, 20 Feb 2012 12:47:14 +0100
changeset 812 0153b3ad2308
parent 811 b46fb7e23870
child 813 7cfec468bed5
[visualisation] graph of time taken by tests in "test reports" tabs (closes #2176598) using clickable charts by testconfig/branch in the "test results" tab view (with filter when not enough results)
__pkginfo__.py
data/cubes.apycot.css
i18n/en.po
i18n/fr.po
views/plots.py
views/tracker.py
--- a/__pkginfo__.py	Wed Feb 22 09:19:25 2012 +0100
+++ b/__pkginfo__.py	Mon Feb 20 12:47:14 2012 +0100
@@ -24,6 +24,7 @@
                'cubicweb-vcsfile': '>= 1.6.1',
                'cubicweb-file': None,
                'cubicweb-narval': '>= 3.0.2',
+               'cubicweb-jqplot': '>= 0.2.0',
                }
 __recommends__ = {'cubicweb-tracker': None,
                   'cubicweb-nosylist': '>= 0.5.0'}
--- a/data/cubes.apycot.css	Wed Feb 22 09:19:25 2012 +0100
+++ b/data/cubes.apycot.css	Mon Feb 20 12:47:14 2012 +0100
@@ -214,3 +214,7 @@
     background-color : transparent ;
     border: none;
 }
+
+table.plotlegend td{
+    padding : 0 5px 0 10px
+}
\ No newline at end of file
--- a/i18n/en.po	Wed Feb 22 09:19:25 2012 +0100
+++ b/i18n/en.po	Mon Feb 20 12:47:14 2012 +0100
@@ -873,6 +873,9 @@
 msgid "when this test config should be started"
 msgstr ""
 
+msgid "Time taken by Test Executions"
+msgstr ""
+
 #~ msgid "boxes_apycot.te.download_box"
 #~ msgstr "download box"
 
--- a/i18n/fr.po	Wed Feb 22 09:19:25 2012 +0100
+++ b/i18n/fr.po	Mon Feb 20 12:47:14 2012 +0100
@@ -894,4 +894,8 @@
 msgstr "chaque semaine"
 
 msgid "when this test config should be started"
-msgstr "quand cette configuration doit-ellle être lancée"
+msgstr "quand cette configuration doit-elle être lancée"
+
+msgid "Time taken by Test Executions"
+msgstr "Temps d'exécution des tests"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/plots.py	Mon Feb 20 12:47:14 2012 +0100
@@ -0,0 +1,58 @@
+"""this module contains some plot report views for test execution results
+
+:organization: Logilab
+:copyright: 2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+:license: General Public License version 2 - http://www.gnu.org/licenses
+"""
+__docformat__ = "restructuredtext en"
+_ = unicode
+
+from cubes.jqplot.views import JQPlotSimpleView
+from cubicweb.selectors import multi_columns_rset
+
+ERROR_CODES = {
+    'error': "#FF5555",
+    'failure': "#FF8844",
+    'partial': "#FFFF55",
+    'success': "#33FF33",
+    'other': "#AAAAAA",
+    }
+
+class JQPlotTestExecutionView(JQPlotSimpleView):
+    __regid__ = 'jqplot.testexecution'
+    __select__ = multi_columns_rset(3)
+    default_renderer = 'bar'
+
+    onload = '''%(id)s = $.jqplot("%(id)s", %(data)s, %(options)s);
+
+    $(document).ready(function(){
+        $("#%(id)s").bind('jqplotDataClick',
+            function (ev, seriesIndex, pointIndex, data) {
+            	/* To open in a NEW window use: */
+                if ( ev.which == 2 ) {
+            	   window.open(data[2]);
+                } else  {
+                   /* To open in the same window use: */
+              	   window.location.href=data[2];
+                };
+            }
+        );
+    });
+    '''
+    default_options = {
+        'varyBarColor': True,
+        'barMargin':0,
+        }
+    default_legend = {
+        'show': False,
+        }
+
+    def get_data(self):
+        return [[i+1,x[1],self._cw.build_url(x[0])] for i,x in enumerate(self.cw_rset.rows)]
+
+    def set_custom_options(self, options):
+        other = ERROR_CODES.get('other')
+        options['seriesColors'] = [ERROR_CODES.get(x[2], other) for x in self.cw_rset.rows]
+        #FIXME hack to approximate width since it doesn't work in js
+        options['series'][0]['rendererOptions']['barWidth'] = 350/len(self.cw_rset.rows)
--- a/views/tracker.py	Wed Feb 22 09:19:25 2012 +0100
+++ b/views/tracker.py	Mon Feb 20 12:47:14 2012 +0100
@@ -1,7 +1,7 @@
 """this module contains some stuff to integrate the apycot cube into jpl
 
 :organization: Logilab
-:copyright: 2009-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2009-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 :license: General Public License version 2 - http://www.gnu.org/licenses
 """
@@ -12,15 +12,45 @@
 from cubicweb.view import EntityView
 from cubicweb.web import uicfg
 
+from cubes.apycot.views.plots import ERROR_CODES
+
 _pvs = uicfg.primaryview_section
 _pvs.tag_subject_of(('Project', 'has_apycot_environment', '*'), 'attributes')
 
+# in graphs ignore branches that have less MIN_NB_RUNS_IN_GRAPH
+MIN_NB_RUNS_IN_GRAPH = 3
+
 class ProjectTestResultsTab(EntityView):
-    """display project's documentation"""
+    """display project's test execution results"""
     __regid__ = title = _('apycottestresults_tab')
     __select__ = is_instance('Project')
 
     def entity_call(self, entity):
+        self.w(u'<h3>%s</h3>' % _('Time taken by Test Executions'))
+        self.w(u'''<table class="plotlegend"><tr>%s</tr></table>
+        ''' % ''.join(['<td>%s</td><td style="background:%s">&nbsp;&nbsp;&nbsp;</td>' % (x,y) for x,y in  ERROR_CODES.items()]))
+        testconfig_rset = self._cw.execute('Any TC,NAME WHERE P has_apycot_environment TENV, '
+                                           'TC use_environment TENV, P eid %(p)s, TC name NAME',  {'p': entity.eid})
+        branches_rset = self._cw.execute('Any B GROUPBY B WHERE TE branch B, '
+                                         'TE is TestExecution, TE using_environment TENV, '
+                                         'P has_apycot_environment TENV, P eid %(p)s HAVING COUNT(TE) > %(limit)s',
+                                         {'p':entity.eid,
+                                          'limit':MIN_NB_RUNS_IN_GRAPH})
+        for testconfig in testconfig_rset:
+            for branch in branches_rset:
+                label = '%s : %s - %s' % (_(u'Test run time'), testconfig[1], branch[0])
+                rset = self._cw.execute(
+            'Any TE,  ET - ST, S ORDERBY ST LIMIT 50 WHERE '
+            'TE is TestExecution, TE using_environment TENV, '
+            'P has_apycot_environment TENV, TE starttime ST, '
+            'TE endtime ET, TE eid E, TE status S, P eid %(p)s, '
+            'TE using_config TC, TC eid %(tc)s, TE branch %(branch)s',
+                {'p': entity.eid,
+                 'tc': testconfig[0],
+                 'branch':branch[0]})
+                if rset and len(rset) > MIN_NB_RUNS_IN_GRAPH:
+                    self.w(u'<h4>%s</h4>' % label)
+                    self.wview('jqplot.testexecution', rset, 'noresult')
         rset = self._cw.execute(
             'Any T,TC,T,TB,TST,TET,TF, TS ORDERBY TST DESC WHERE '
             'T status TS, T using_config TC, T branch TB, '
@@ -49,10 +79,12 @@
 #         self.wview('summary', configsrset, title=self._cw._(self.title))
 
 
-try:
-    from cubes.tracker.views.project import ProjectPrimaryView
-except ImportError:
-    pass
-else:
-    if 'apycottestresults_tab' not in ProjectPrimaryView.tabs:
-        ProjectPrimaryView.tabs.append('apycottestresults_tab')
+def registration_callback(vreg):
+    try:
+        from cubes.tracker.views.project import ProjectPrimaryView
+    except ImportError:
+        pass
+    else:
+        vreg.register_all(globals().values(), __name__)
+        if 'apycottestresults_tab' not in ProjectPrimaryView.tabs:
+            ProjectPrimaryView.tabs.append('apycottestresults_tab')