Commits

seccanj committed f8720ea

Added full test plan view (feature request 3076739 on SourceForge).

  • Participants
  • Parent commits 519baa2

Comments (0)

Files changed (10)

+rm -rf bin
+
+cd tracgenericclass/trunk
+rm -rf build dist *.egg-info
+
+cd ../../tracgenericworkflow/trunk
+rm -rf build dist *.egg-info
+
+cd ../../sqlexecutor/trunk
+rm -rf build dist *.egg-info
+
+cd ../../testman4trac/trunk
+rm -rf build dist *.egg-info
+
+cd ../..
+VER=$1
+
+zip -r testman4trac.$VER.zip bin

testman4trac/trunk/setup.py

 
 setup(
     name='TestManager',
-    version='1.3.1',
+    version='1.3.2',
     packages=['testmanager'],
     package_data={'testmanager' : ['*.txt', 'templates/*.html', 'htdocs/js/*.js', 'htdocs/css/*.css', 'htdocs/images/*.*']},
     author = 'Roberto Longobardi, Marco Cipriani',

testman4trac/trunk/testmanager/README.txt

 
 (Refer to the tickets on trac-hacks for complete descriptions.)
 
+Release 1.3.2 (2010-10-03):
+  o Added feature 3076739 (SourceForge): Full Test Plan display / print
+
+Release 1.3.1 (2010-10-02):
+  o Fixed a base-code bug that prevented test catalog modification with a PostgreSQL binding. (Thanks Rodel for reporting it).
+
 Release 1.3.0 (2010-10-01):
   o The base Test Manager plugin has been separated and other plugins have been created to embed the functionalities of generic class framework and the workflow engine.
     Now we have four plugins:

testman4trac/trunk/testmanager/api.py

                     tcip.save_changes(author, "Status changed")
                 else:
                     tcip['page_name'] = path
-                    tcip['status'] = status
+                    tcip.set_status(status, author)
                     tcip.insert()
                 
             except:

testman4trac/trunk/testmanager/htdocs/images/tree.png

Added
New image

testman4trac/trunk/testmanager/htdocs/images/tree_table.png

Added
New image

testman4trac/trunk/testmanager/macros.py

 
 from genshi.builder import tag
 
+from datetime import datetime
+
 from trac.core import *
 from trac.wiki.macros import WikiMacroBase
 from trac.wiki.api import WikiSystem, parse_args
         
         req = formatter.req
 
-        return _build_testplan_tree(self.env, req, planid, catpath)
+        return _build_testplan_tree(self.env, req, planid, catpath, mode='tree')
+
+
+class TestPlanTreeTableMacro(WikiMacroBase):
+    """Display a tree table with catalogs and test cases in a test plan. 
+       Includes test case status in the plan.
+
+    Usage:
+
+    {{{
+    [[TestPlanTreeTable(planid=<Plan ID>, catalog_path=<Catalog path>)]]
+    }}}
+    """
+    
+    def expand_macro(self, formatter, name, content):
+        args, kw = parse_args(content)
+
+        planid = kw.get('planid', -1)
+        catpath = kw.get('catalog_path', 'TC')
+        
+        req = formatter.req
+
+        return _build_testplan_tree(self.env, req, planid, catpath, mode='tree_table')
 
 
 class TestPlanListMacro(WikiMacroBase):
     text +='</div>'
     return text
     
-def _build_testplan_tree(env, req, planid, curpage):
+def _build_testplan_tree(env, req, planid, curpage, mode='tree'):
     # Determine current catalog name
     cat_name = 'TC'
     if curpage.find('_TC') >= 0:
         cat_name = curpage.rpartition('_TC')[0].rpartition('_')[2]
     elif not curpage == 'TC':
         cat_name = curpage.rpartition('_')[2]
+
+    tp = TestPlan(env, planid)
+
     # Create the catalog subtree model
     components = {'name': curpage, 'childrenC': {},'childrenT': {}, 'tot': 0}
 
                 tc_id = tc.partition('TC')[2]
                 tcip = TestCaseInPlan(env, tc_id, planid)
                 if tcip.exists:
-                    status = tcip['status']
+                    for ts, author, status in tcip.list_history():
+                        break
+                    
+                    if not isinstance(ts, datetime):
+                        ts = from_any_timestamp(ts)
+
                 else:
+                    ts = tp['time']
+                    author = tp['author']
                     status = 'TO_BE_TESTED'
                     
-                parent['childrenT'][tc]={'id':curr_path, 'title': subpage_title, 'status': status}
+                parent['childrenT'][tc]={'id':curr_path, 'title': subpage_title, 'status': status, 'ts': ts, 'author': author}
                 compLoop = parent
                 while (True):
                     compLoop['tot']+=1
     ind = {'count': 0}
     text = ''
 
-    text +='<div style="padding: 0px 0px 10px 10px">'+LABELS['filter_label']+' <input id="tcFilter" title="'+LABELS['filter_help']+'" type="text" size="40" onkeyup="starthighlight(this.value)"/>&nbsp;&nbsp;<span id="searchResultsNumberId" style="font-weight: bold;"></span></div>'
-    text +='<div style="font-size: 0.8em;padding-left: 10px"><a style="margin-right: 10px" onclick="toggleAll(true)" href="javascript:void(0)">'+LABELS['expand_all']+'</a><a onclick="toggleAll(false)" href="javascript:void(0)">'+LABELS['collapse_all']+'</a></div>';
-    text +='<div id="ticketContainer">'
+    if mode == 'tree':
+        text +='<div style="padding: 0px 0px 10px 10px">'+LABELS['filter_label']+' <input id="tcFilter" title="'+LABELS['filter_help']+'" type="text" size="40" onkeyup="starthighlight(this.value)"/>&nbsp;&nbsp;<span id="searchResultsNumberId" style="font-weight: bold;"></span></div>'
+        text +='<div style="font-size: 0.8em;padding-left: 10px"><a style="margin-right: 10px" onclick="toggleAll(true)" href="javascript:void(0)">'+LABELS['expand_all']+'</a><a onclick="toggleAll(false)" href="javascript:void(0)">'+LABELS['collapse_all']+'</a></div>';
+        text +='<div id="ticketContainer">'
+        text += _render_subtree(planid, components, ind, 0)
+        text +='</div>'
 
-    text += _render_subtree(planid, components, ind, 0)
-    
-    text +='</div>'
+    elif mode == 'tree_table':
+        text += '<form id="testPlan"><fieldset id="testPlanFields" class="expanded">'
+        text += '<table class="listing"><thead><tr>';
+        text += '<th>'+"Name"+'</th><th>'+"Status"+'</th><th>'+"Author"+'</th><th>'+"Last Change"+'</th>'
+        text += '</tr></thead><tbody>';        
+        text += _render_subtree_as_table(planid, components, ind, 0)
+        text += '</tbody></table>'
+        text += '</fieldset></form>'
+
     return text
 
 
         text+='</ul>'        
     return text
 
-
 def _render_testcases(planid, data): 
     text=''
     keyList = data.keys()
             text+="<li style='font-weight: normal;' onmouseover='showPencil(\"pencilIcon"+tick['id']+"\", true)' onmouseout='hidePencil(\"pencilIcon"+tick['id']+"\", false)'><a href='"+tick['id']+"' target='_blank'>"+tick['title']+"&nbsp;</a><span><a class='rightIcon' style='display: none;' title='"+LABELS['edit_test_case_label']+"' href='"+tick['id']+"?action=edit' target='_blank' id='pencilIcon"+tick['id']+"'></a></span></li>"
             
     return text
-    
-    
+        
 def _build_testcase_status(env, req, planid, curpage):
     tc_id = curpage.rpartition('_TC')[2]
     
     text += '<img style="display: '+display['SUCCESSFUL']+';" id="tcTitleStatusIconSUCCESSFUL" src="../chrome/testmanager/images/green.png" title="'+LABELS['SUCCESSFUL']+'"></img></span>'
     
     return text
+    
+# Render the subtree as a tree table
+def _render_subtree_as_table(planid, component, ind, level, path=''):
+    data = component
+    text = ''
 
-    
+    if (level == 0):
+        data = component['childrenC']
+
+    keyList = data.keys()
+    sortedList = sorted(keyList)
+    for x in sortedList:
+        ind['count'] += 1
+        comp = data[x]
+        fullpath = path+x+" - "
+        if ('childrenC' in comp):
+            subcData=comp['childrenC']
+            
+            index = str(ind['count'])
+            
+            text += '<tr><td style="padding-left: '+str(level*30)+'px;"><a href="'+comp['id']+'" title="'+LABELS['open']+'">'+comp['title']+'</a></td><td></td><td></td><td></td></tr>'
+            ind['count']+=1
+            text+=_render_subtree_as_table(planid, subcData, ind, level+1, fullpath)
+            if ('childrenT' in comp):            
+                mtData=comp['childrenT']
+                text+=_render_testcases_as_table(planid, mtData, level+1)
+
+    if (level == 0):
+        if ('childrenT' in component):            
+            cmtData=component['childrenT']
+            text+=_render_testcases_as_table(planid, cmtData, level+1)
+
+    return text
+
+def _render_testcases_as_table(planid, data, level=0): 
+    text=''
+    keyList = data.keys()
+    sortedList = sorted(keyList)
+    for x in sortedList:
+        tick = data[x]
+        status = tick['status']
+        has_status = True
+        if status == 'SUCCESSFUL':
+            statusIcon='../chrome/testmanager/images/green.png'
+        elif status == 'FAILED':
+            statusIcon='../chrome/testmanager/images/red.png'
+        elif status == 'TO_BE_TESTED':
+            statusIcon='../chrome/testmanager/images/yellow.png'
+        else:
+            has_status = False
+
+        if has_status:
+            statusLabel = LABELS[status]
+            text += '<tr><td style="padding-left: '+str(level*30)+'px;"><img class="iconElement" src="'+statusIcon+'" title="'+statusLabel+'"></img><a href="'+tick['id']+'?planid='+planid+'&mode=tree_table" target="_blank">'+tick['title']+'</a></td><td>'+statusLabel+'</td><td>'+tick['author']+'</td><td>'+str(tick['ts'])+'</td></tr>'
+        else:
+            text += '<tr><td style="padding-left: '+str(level*30)+'px;">'+tick['title']+'</td></tr>'
+            
+    return text
+        
 def _build_testcase_change_status(env, req, planid, curpage):
     tc_id = curpage.rpartition('_TC')[2]
     

testman4trac/trunk/testmanager/wiki.py

 
 from tracgenericclass.model import GenericClassModelProvider
 
-from testmanager.macros import TestCaseBreadcrumbMacro, TestCaseTreeMacro, TestPlanTreeMacro, TestPlanListMacro, TestCaseStatusMacro, TestCaseChangeStatusMacro, TestCaseStatusHistoryMacro
+from testmanager.macros import TestCaseBreadcrumbMacro, TestCaseTreeMacro, TestPlanTreeMacro, TestPlanTreeTableMacro, TestPlanListMacro, TestCaseStatusMacro, TestCaseChangeStatusMacro, TestCaseStatusHistoryMacro
 from testmanager.labels import *
 from testmanager.model import TestCatalog, TestCase, TestCaseInPlan, TestPlan
 
         path_name = req.path_info
         cat_name = path_name.rpartition('/')[2]
         cat_id = cat_name.rpartition('TT')[2]
+        
+        mode = req.args.get('mode', 'tree')
 
         tmmodelprovider = GenericClassModelProvider(self.env)
         test_plan = TestPlan(self.env, planid, cat_id, page_name)
         add_script(req, 'testmanager/js/labels.js')
         add_script(req, 'testmanager/js/testmanager.js')
 
-        tree_macro = TestPlanTreeMacro(self.env)
+        if mode == 'tree':
+            tree_macro = TestPlanTreeMacro(self.env)
+        elif mode == 'tree_table':
+            tree_macro = TestPlanTreeTableMacro(self.env)
+            
         tp = TestPlan(self.env, planid)
         
         insert1 = tag.div()(
                     tag.a(href=req.href.wiki(page_name))(LABELS['back_to_catalog']),
-                    tag.br(), tag.br(), tag.br(), 
+                    tag.div(style='border: 1px, solid, gray; padding: 1px;')(
+                        tag.span()(
+                            tag.a(href=req.href.wiki(page_name, mode='tree', planid=planid))(
+                                tag.img(src='../chrome/testmanager/images/tree.png', title="Tree View"))
+                            ),
+                        tag.span()(
+                            tag.a(href=req.href.wiki(page_name, mode='tree_table', planid=planid))(
+                                tag.img(src='../chrome/testmanager/images/tree_table.png', title="Table View"))
+                            )),
+                    tag.br(), 
                     tag.h1(LABELS['test_plan']+tp['name'])
                     )
 
         tc_name = page_name
         cat_name = page_name.partition('_TC')[0]
         
+        mode = req.args.get('mode', 'tree')
+
         has_status = True
         tp = TestPlan(self.env, planid)
         plan_name = tp['name']
         add_script(req, 'testmanager/js/testmanager.js')
         
         insert1 = tag.div()(
-                    self._get_breadcrumb_markup(formatter, planid, page_name),
+                    self._get_breadcrumb_markup(formatter, planid, page_name, mode),
                     tag.br(), tag.br(), tag.br(), 
                     tag.span(style='font-size: large; font-weight: bold;')(
                         self._get_testcase_status_markup(formatter, has_status, page_name, planid),
                     
         return stream | Transformer('//div[contains(@class,"wikipage")]').after(insert2) | Transformer('//div[contains(@class,"wikipage")]').before(insert1)
     
-    def _get_breadcrumb_markup(self, formatter, planid, page_name):
+    def _get_breadcrumb_markup(self, formatter, planid, page_name, mode='tree'):
         if planid and not planid == '-1':
             # We are in the context of a test plan
             if not page_name.rpartition('_TC')[2] == '':
                 # It's a test case
                 tp = TestPlan(self.env, planid)
                 catpath = tp['page_name']
-                return tag.a(href=formatter.req.href.wiki(catpath, planid=planid))(LABELS['back_to_plan'])
+                return tag.a(href=formatter.req.href.wiki(catpath, planid=planid, mode=mode))(LABELS['back_to_plan'])
             else:
                 # It's a test plan
                 return tag.a(href=formatter.req.href.wiki(page_name))(LABELS['back_to_catalog'])

tracgenericclass/trunk/tracgenericclass/model.py

         return fields
         
     def get_metadata(self, realm):
-        self.env.log.debug(">>> get_metadata")
-
         tmp_metadata = self.metadata()
         if realm in tmp_metadata:
             metadata = copy.deepcopy(tmp_metadata[realm])
         else:
             metadata = None
 
-        self.env.log.debug("<<< get_metadata")
         return metadata
         
     def fields(self):
         """Return the list of fields available for every realm."""
 
-        self.env.log.debug(">>> fields")
-
         if not self.all_fields:
             fields = {}
 
                     if 'custom' in f:
                         self.env.log.debug("     (custom)")
 
-        self.env.log.debug("<<< fields")
-
         return self.all_fields
         
     def metadata(self):
         """Return metadata information about concrete classes."""
 
-        self.env.log.debug(">>> metadata")
-
         if not self.all_metadata:
             metadata = {}
 
 
             self.all_metadata = metadata
 
-        self.env.log.debug("<<< metadata")
-
         return self.all_metadata
 
     def append_custom_fields(self, fields, custom_fields):
     def custom_fields(self, realm):
         """Return the list of available custom fields."""
         
-        self.env.log.debug(">>> custom_fields")
-        
         if not realm in self.all_custom_fields:
             fields = []
             config = self.config[realm+'-tm_custom']
             fields.sort(lambda x, y: cmp(x['order'], y['order']))
             
             self.all_custom_fields[realm] = fields
-
-        self.env.log.debug("<<< custom_fields")
             
         return self.all_custom_fields[realm]