VirtualBox

Changeset 61250 in vbox for trunk


Ignore:
Timestamp:
May 27, 2016 6:00:16 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107541
Message:

testmanager: Some failure reason improvments.

Location:
trunk/src/VBox/ValidationKit/testmanager
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/testmanager/core/failurecategory.py

    r61220 r61250  
    3131
    3232# Validation Kit imports.
    33 from testmanager.core.base          import ModelDataBase, ModelLogicBase, TMRowInUse, TMInvalidData, TMRowNotFound;
     33from testmanager.core.base          import ModelDataBase, ModelLogicBase, TMRowInUse, TMInvalidData, TMRowNotFound, \
     34                                           ChangeLogEntry, AttributeChangeEntry;
     35from testmanager.core.useraccount   import UserAccountLogic;
    3436
    3537
     
    137139            aoRows.append(FailureCategoryData().initFromDbRow(aoRow))
    138140        return aoRows
     141
     142
     143    def fetchForChangeLog(self, idFailureCategory, iStart, cMaxRows, tsNow): # pylint: disable=R0914
     144        """
     145        Fetches change log entries for a failure reason.
     146
     147        Returns an array of ChangeLogEntry instance and an indicator whether
     148        there are more entries.
     149        Raises exception on error.
     150        """
     151        if tsNow is None:
     152            tsNow = self._oDb.getCurrentTimestamp();
     153
     154        # 1. Get a list of the relevant changes.
     155        self._oDb.execute('SELECT * FROM FailureCategories WHERE idFailureCategory = %s AND tsEffective <= %s\n'
     156                          'ORDER BY tsEffective DESC\n'
     157                          'LIMIT %s OFFSET %s\n'
     158                          , ( idFailureCategory, tsNow, cMaxRows + 1, iStart, ));
     159        aoRows = [];
     160        for aoChange in self._oDb.fetchAll():
     161            aoRows.append(FailureCategoryData().initFromDbRow(aoChange));
     162
     163        # 2. Calculate the changes.
     164        aoEntries = [];
     165        for i in xrange(0, len(aoRows) - 1):
     166            oNew = aoRows[i];
     167            oOld = aoRows[i + 1];
     168
     169            aoChanges = [];
     170            for sAttr in oNew.getDataAttributes():
     171                if sAttr not in [ 'tsEffective', 'tsExpire', 'uidAuthor', ]:
     172                    oOldAttr = getattr(oOld, sAttr);
     173                    oNewAttr = getattr(oNew, sAttr);
     174                    if oOldAttr != oNewAttr:
     175                        aoChanges.append(AttributeChangeEntry(sAttr, oNewAttr, oOldAttr, str(oNewAttr), str(oOldAttr)));
     176
     177            aoEntries.append(ChangeLogEntry(oNew.uidAuthor, None, oNew.tsEffective, oNew.tsExpire, oNew, oOld, aoChanges));
     178
     179        # If we're at the end of the log, add the initial entry.
     180        if len(aoRows) <= cMaxRows and len(aoRows) > 0:
     181            oNew = aoRows[-1];
     182            aoEntries.append(ChangeLogEntry(oNew.uidAuthor, None, oNew.tsEffective, oNew.tsExpire, oNew, None, []));
     183
     184        return (UserAccountLogic(self._oDb).resolveChangeLogAuthors(aoEntries), len(aoRows) > cMaxRows);
     185
    139186
    140187    def getFailureCategoriesForCombo(self, tsEffective = None):
  • trunk/src/VBox/ValidationKit/testmanager/core/failurereason.py

    r61220 r61250  
    3131
    3232# Validation Kit imports.
    33 from testmanager.core.base              import ModelDataBase, ModelLogicBase, TMRowNotFound, TMInvalidData, TMRowInUse;
     33from testmanager.core.base              import ModelDataBase, ModelLogicBase, TMRowNotFound, TMInvalidData, TMRowInUse, \
     34                                               AttributeChangeEntry, ChangeLogEntry;
    3435from testmanager.core.useraccount       import UserAccountLogic;
    3536
     
    151152        Fetches Failure Category records.
    152153
    153         Returns an array (list) of FailureReasonData items, empty list if none.
     154        Returns an array (list) of FailureReasonDataEx items, empty list if none.
    154155        Raises exception on error.
    155156        """
     157        self._ensureCachesPresent();
     158
     159        if tsNow is None:
     160            self._oDb.execute('SELECT   FailureReasons.*,\n'
     161                              '         FailureCategories.sShort AS sCategory\n'
     162                              'FROM     FailureReasons,\n'
     163                              '         FailureCategories\n'
     164                              'WHERE    FailureReasons.tsExpire             = \'infinity\'::TIMESTAMP\n'
     165                              '     AND FailureCategories.idFailureCategory = FailureReasons.idFailureCategory\n'
     166                              '     AND FailureCategories.tsExpire          = \'infinity\'::TIMESTAMP\n'
     167                              'ORDER BY sCategory ASC, sShort ASC\n'
     168                              'LIMIT %s OFFSET %s\n'
     169                              , (cMaxRows, iStart,));
     170        else:
     171            self._oDb.execute('SELECT   FailureReasons.*,\n'
     172                              '         FailureCategories.sShort AS sCategory\n'
     173                              'FROM     FailureReasons,\n'
     174                              '         FailureCategories\n'
     175                              'WHERE    FailureReasons.tsExpire     > %s\n'
     176                              '     AND FailureReasons.tsEffective <= %s\n'
     177                              '     AND FailureCategories.idFailureCategory = FailureReasons.idFailureCategory\n'
     178                              '     AND FailureReasons.tsExpire     > %s\n'
     179                              '     AND FailureReasons.tsEffective <= %s\n'
     180                              'ORDER BY sCategory ASC, sShort ASC\n'
     181                              'LIMIT %s OFFSET %s\n'
     182                              , (tsNow, tsNow, tsNow, tsNow, cMaxRows, iStart,));
     183
     184        aoRows = []
     185        for aoRow in self._oDb.fetchAll():
     186            aoRows.append(FailureReasonDataEx().initFromDbRowEx(aoRow, self.oCategoryLogic, self.oUserAccountLogic));
     187        return aoRows
     188
     189    def fetchForListingInCategory(self, iStart, cMaxRows, tsNow, idFailureCategory):
     190        """
     191        Fetches Failure Category records.
     192
     193        Returns an array (list) of FailureReasonDataEx items, empty list if none.
     194        Raises exception on error.
     195        """
     196        self._ensureCachesPresent();
    156197
    157198        if tsNow is None:
    158199            self._oDb.execute('SELECT   *\n'
    159200                              'FROM     FailureReasons\n'
    160                               'WHERE    tsExpire = \'infinity\'::TIMESTAMP\n'
    161                               'ORDER BY idFailureReason DESC\n'
     201                              'WHERE    tsExpire          = \'infinity\'::TIMESTAMP\n'
     202                              '     AND idFailureCategory = %s\n'
     203                              'ORDER BY sShort ASC\n'
    162204                              'LIMIT %s OFFSET %s\n'
    163                               , (cMaxRows, iStart,));
     205                              , ( idFailureCategory, cMaxRows, iStart,));
    164206        else:
    165207            self._oDb.execute('SELECT   *\n'
    166208                              'FROM     FailureReasons\n'
    167                               'WHERE    tsExpire     > %s\n'
    168                               '     AND tsEffective <= %s\n'
    169                               'ORDER BY idFailureReason DESC\n'
     209                              'WHERE    idFailureCategory = %s\n'
     210                              '     AND tsExpire          > %s\n'
     211                              '     AND tsEffective      <= %s\n'
     212                              'ORDER BY sShort ASC\n'
    170213                              'LIMIT %s OFFSET %s\n'
    171                               , (tsNow, tsNow, cMaxRows, iStart,));
     214                              , ( tsNow, tsNow, idFailureCategory, cMaxRows, iStart,));
    172215
    173216        aoRows = []
    174217        for aoRow in self._oDb.fetchAll():
    175             aoRows.append(FailureReasonData().initFromDbRow(aoRow))
     218            aoRows.append(FailureReasonDataEx().initFromDbRowEx(aoRow, self.oCategoryLogic, self.oUserAccountLogic));
    176219        return aoRows
    177220
     
    204247        return [(-1, sFirstEntry, '')] + aoRows;
    205248
     249
     250    def fetchForChangeLog(self, idFailureReason, iStart, cMaxRows, tsNow): # pylint: disable=R0914
     251        """
     252        Fetches change log entries for a failure reason.
     253
     254        Returns an array of ChangeLogEntry instance and an indicator whether
     255        there are more entries.
     256        Raises exception on error.
     257        """
     258        self._ensureCachesPresent();
     259
     260        if tsNow is None:
     261            tsNow = self._oDb.getCurrentTimestamp();
     262
     263        # 1. Get a list of the relevant changes.
     264        self._oDb.execute('SELECT * FROM FailureReasons WHERE idFailureReason = %s AND tsEffective <= %s\n'
     265                          'ORDER BY tsEffective DESC\n'
     266                          'LIMIT %s OFFSET %s\n'
     267                          , ( idFailureReason, tsNow, cMaxRows + 1, iStart, ));
     268        aoRows = [];
     269        for aoChange in self._oDb.fetchAll():
     270            aoRows.append(FailureReasonData().initFromDbRow(aoChange));
     271
     272        # 2. Calculate the changes.
     273        aoEntries = [];
     274        for i in xrange(0, len(aoRows) - 1):
     275            oNew = aoRows[i];
     276            oOld = aoRows[i + 1];
     277
     278            aoChanges = [];
     279            for sAttr in oNew.getDataAttributes():
     280                if sAttr not in [ 'tsEffective', 'tsExpire', 'uidAuthor', ]:
     281                    oOldAttr = getattr(oOld, sAttr);
     282                    oNewAttr = getattr(oNew, sAttr);
     283                    if oOldAttr != oNewAttr:
     284                        if sAttr == 'idFailureCategory':
     285                            oCat = self.oCategoryLogic.cachedLookup(oOldAttr);
     286                            if oCat is not None:
     287                                oOldAttr = '%s (%s)' % (oOldAttr, oCat.sShort, );
     288                            oCat = self.oCategoryLogic.cachedLookup(oNewAttr);
     289                            if oCat is not None:
     290                                oNewAttr = '%s (%s)' % (oNewAttr, oCat.sShort, );
     291                        aoChanges.append(AttributeChangeEntry(sAttr, oNewAttr, oOldAttr, str(oNewAttr), str(oOldAttr)));
     292
     293            aoEntries.append(ChangeLogEntry(oNew.uidAuthor, None, oNew.tsEffective, oNew.tsExpire, oNew, oOld, aoChanges));
     294
     295        # If we're at the end of the log, add the initial entry.
     296        if len(aoRows) <= cMaxRows and len(aoRows) > 0:
     297            oNew = aoRows[-1];
     298            aoEntries.append(ChangeLogEntry(oNew.uidAuthor, None, oNew.tsEffective, oNew.tsExpire, oNew, None, []));
     299
     300        return (UserAccountLogic(self._oDb).resolveChangeLogAuthors(aoEntries), len(aoRows) > cMaxRows);
     301
     302
    206303    def getById(self, idFailureReason):
    207304        """Get Failure Reason data by idFailureReason"""
     
    333430
    334431            if self._oDb.getRowCount() == 1:
    335                 if self.oCategoryLogic is None:
    336                     from testmanager.core.failurecategory import FailureCategoryLogic;
    337                     self.oCategoryLogic = FailureCategoryLogic(self._oDb);
    338                 if self.oUserAccountLogic is None:
    339                     self.oUserAccountLogic = UserAccountLogic(self._oDb);
     432                self._ensureCachesPresent();
    340433                oEntry = FailureReasonDataEx().initFromDbRowEx(self._oDb.fetchOne(), self.oCategoryLogic,
    341434                                                               self.oUserAccountLogic);
     
    386479        return True;
    387480
     481
     482    def _ensureCachesPresent(self):
     483        """ Ensures we've got the cache references resolved. """
     484        if self.oCategoryLogic is None:
     485            from testmanager.core.failurecategory import FailureCategoryLogic;
     486            self.oCategoryLogic = FailureCategoryLogic(self._oDb);
     487        if self.oUserAccountLogic is None:
     488            self.oUserAccountLogic = UserAccountLogic(self._oDb);
     489        return True;
     490
     491
  • trunk/src/VBox/ValidationKit/testmanager/core/testresults.py

    r61220 r61250  
    3838from testmanager                    import config;
    3939from testmanager.core.base          import ModelDataBase, ModelLogicBase, ModelDataBaseTestCase, TMExceptionBase, \
    40                                            TMTooManyRows, TMInvalidData, TMRowNotFound, TMRowAlreadyExists;
     40                                           TMTooManyRows, TMInvalidData, TMRowNotFound, TMRowAlreadyExists, \
     41                                           ChangeLogEntry, AttributeChangeEntry;
    4142from testmanager.core.testgroup     import TestGroupData;
    4243from testmanager.core.build         import BuildDataEx;
    43 from testmanager.core.failurereason import FailureReasonLogic;
     44from testmanager.core.failurereason import FailureReasonLogic, FailureReasonData;
    4445from testmanager.core.testbox       import TestBoxData;
    4546from testmanager.core.testcase      import TestCaseData;
     
    126127        return self;
    127128
     129    def initFromDbWithId(self, oDb, idTestResult, tsNow = None, sPeriodBack = None):
     130        """
     131        Initialize from the database, given the ID of a row.
     132        """
     133        _ = tsNow;
     134        _ = sPeriodBack;
     135        oDb.execute('SELECT *\n'
     136                    'FROM   TestResults\n'
     137                    'WHERE  idTestResult = %s\n'
     138                    , ( idTestResult,));
     139        aoRow = oDb.fetchOne()
     140        if aoRow is None:
     141            raise TMRowNotFound('idTestResult=%s not found' % (idTestResult,));
     142        return self.initFromDbRow(aoRow);
     143
    128144    def isFailure(self):
    129145        """ Check if it's a real failure. """
     
    430446    kasAllowNullAttributes      = ['tsEffective', 'tsExpire', 'uidAuthor', 'sComment' ];
    431447
     448    kcDbColumns                 = 6;
     449
    432450    def __init__(self):
    433451        ModelDataBase.__init__(self)
     
    467485        if aoRow is None:
    468486            raise TMRowNotFound('idTestResult=%s not found (tsNow=%s, sPeriodBack=%s)' % (idTestResult, tsNow, sPeriodBack));
     487        assert len(aoRow) == self.kcDbColumns;
    469488        return self.initFromDbRow(aoRow);
    470489
     
    19221941        ModelLogicBase.__init__(self, oDb)
    19231942
     1943    def fetchForChangeLog(self, idTestResult, iStart, cMaxRows, tsNow): # pylint: disable=R0914
     1944        """
     1945        Fetches change log entries for a failure reason.
     1946
     1947        Returns an array of ChangeLogEntry instance and an indicator whether
     1948        there are more entries.
     1949        Raises exception on error.
     1950        """
     1951
     1952        if tsNow is None:
     1953            tsNow = self._oDb.getCurrentTimestamp();
     1954
     1955        # 1. Get a list of the changes from both TestResultFailures and assoicated
     1956        #    FailureReasons.  The latter is useful since the failure reason
     1957        #    description may evolve along side the invidiual failure analysis.
     1958        self._oDb.execute('( SELECT trf.tsEffective AS tsEffectiveChangeLog,\n'
     1959                          '         trf.uidAuthor   AS uidAuthorChangeLog,\n'
     1960                          '         trf.*,\n'
     1961                          '         fr.*\n'
     1962                          '  FROM   TestResultFailures trf,\n'
     1963                          '         FailureReasons fr\n'
     1964                          '  WHERE  trf.idTestResult = %s\n'
     1965                          '     AND trf.tsEffective <= %s\n'
     1966                          '     AND trf.idFailureReason = fr.idFailureReason\n'
     1967                          '     AND fr.tsEffective      <= trf.tsEffective\n'
     1968                          '     AND fr.tsExpire         >  trf.tsEffective\n'
     1969                          ')\n'
     1970                          'UNION\n'
     1971                          '( SELECT fr.tsEffective AS tsEffectiveChangeLog,\n'
     1972                          '         fr.uidAuthor   AS uidAuthorChangeLog,\n'
     1973                          '         trf.*,\n'
     1974                          '         fr.*\n'
     1975                          '  FROM   TestResultFailures trf,\n'
     1976                          '         FailureReasons fr\n'
     1977                          '  WHERE  trf.idTestResult    = %s\n'
     1978                          '     AND trf.tsEffective    <= %s\n'
     1979                          '     AND trf.idFailureReason = fr.idFailureReason\n'
     1980                          '     AND fr.tsEffective      > trf.tsEffective\n'
     1981                          '     AND fr.tsEffective      < trf.tsExpire\n'
     1982                          ')\n'
     1983                          'ORDER BY tsEffectiveChangeLog DESC\n'
     1984                          'LIMIT %s OFFSET %s\n'
     1985                          , ( idTestResult, tsNow, idTestResult, tsNow, cMaxRows + 1, iStart, ));
     1986
     1987        aaoRows = [];
     1988        for aoChange in self._oDb.fetchAll():
     1989            oTrf = TestResultFailureDataEx().initFromDbRow(aoChange[2:]);
     1990            oFr  = FailureReasonData().initFromDbRow(aoChange[(2+TestResultFailureData.kcDbColumns):]);
     1991            oTrf.oFailureReason = oFr;
     1992            aaoRows.append([aoChange[0], aoChange[1], oTrf, oFr]);
     1993
     1994        # 2. Calculate the changes.
     1995        oFailureCategoryLogic = None;
     1996        aoEntries = [];
     1997        for i in xrange(0, len(aaoRows) - 1):
     1998            aoNew = aaoRows[i];
     1999            aoOld = aaoRows[i + 1];
     2000
     2001            aoChanges = [];
     2002            oNew = aoNew[2];
     2003            oOld = aoOld[2];
     2004            for sAttr in oNew.getDataAttributes():
     2005                if sAttr not in [ 'tsEffective', 'tsExpire', 'uidAuthor', 'oFailureReason', 'oAuthor' ]:
     2006                    oOldAttr = getattr(oOld, sAttr);
     2007                    oNewAttr = getattr(oNew, sAttr);
     2008                    if oOldAttr != oNewAttr:
     2009                        if sAttr == 'idFailureReason':
     2010                            oNewAttr = '%s (%s)' % (oNewAttr, oNew.oFailureReason.sShort, );
     2011                            oOldAttr = '%s (%s)' % (oOldAttr, oOld.oFailureReason.sShort, );
     2012                        aoChanges.append(AttributeChangeEntry(sAttr, oNewAttr, oOldAttr, str(oNewAttr), str(oOldAttr)));
     2013            if oOld.idFailureReason == oNew.idFailureReason:
     2014                oNew = aoNew[3];
     2015                oOld = aoOld[3];
     2016                for sAttr in oNew.getDataAttributes():
     2017                    if sAttr not in [ 'tsEffective', 'tsExpire', 'uidAuthor', ]:
     2018                        oOldAttr = getattr(oOld, sAttr);
     2019                        oNewAttr = getattr(oNew, sAttr);
     2020                        if oOldAttr != oNewAttr:
     2021                            if sAttr == 'idFailureCategory':
     2022                                if oFailureCategoryLogic is None:
     2023                                    from testmanager.core.failurecategory import FailureCategoryLogic;
     2024                                    oFailureCategoryLogic = FailureCategoryLogic(self._oDb);
     2025                                oCat = oFailureCategoryLogic.cachedLookup(oNewAttr);
     2026                                if oCat is not None:
     2027                                    oNewAttr = '%s (%s)' % (oNewAttr, oCat.sShort, );
     2028                                oCat = oFailureCategoryLogic.cachedLookup(oOldAttr);
     2029                                if oCat is not None:
     2030                                    oOldAttr = '%s (%s)' % (oOldAttr, oCat.sShort, );
     2031                            aoChanges.append(AttributeChangeEntry(sAttr, oNewAttr, oOldAttr, str(oNewAttr), str(oOldAttr)));
     2032
     2033
     2034            tsExpire    = aaoRows[i - 1][0] if i > 0 else aoNew[2].tsExpire;
     2035            aoEntries.append(ChangeLogEntry(aoNew[1], None, aoNew[0], tsExpire, aoNew[2], aoOld[2], aoChanges));
     2036
     2037        # If we're at the end of the log, add the initial entry.
     2038        if len(aaoRows) <= cMaxRows and len(aaoRows) > 0:
     2039            aoNew    = aaoRows[-1];
     2040            tsExpire = aaoRows[-1 - 1][0] if len(aaoRows) > 1 else aoNew[2].tsExpire;
     2041            aoEntries.append(ChangeLogEntry(aoNew[1], None, aoNew[0], tsExpire, aoNew[2], None, []));
     2042
     2043        return (UserAccountLogic(self._oDb).resolveChangeLogAuthors(aoEntries), len(aaoRows) > cMaxRows);
     2044
     2045
    19242046    def getById(self, idTestResult):
    19252047        """Get Test result failure reason data by idTestResult"""
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuiadminfailurecategory.py

    r61240 r61250  
    3131
    3232# Validation Kit imports.
    33 from testmanager.webui.wuicontentbase  import WuiFormContentBase, WuiListContentBase, WuiTmLink
    34 from testmanager.core.failurecategory  import FailureCategoryData
     33from testmanager.webui.wuicontentbase           import WuiFormContentBase, WuiContentBase, WuiListContentBase, WuiTmLink;
     34from testmanager.webui.wuiadminfailurereason    import WuiAdminFailureReasonList;
     35from testmanager.core.failurecategory           import FailureCategoryData;
     36from testmanager.core.failurereason             import FailureReasonLogic;
     37
     38
     39class WuiFailureReasonCategoryLink(WuiTmLink):
     40    """ Link to a failure category. """
     41    def __init__(self, idFailureCategory, sName = WuiContentBase.ksShortDetailsLink, sTitle = None, fBracketed = None):
     42        if fBracketed is None:
     43            fBracketed = len(sName) > 2;
     44        from testmanager.webui.wuiadmin import WuiAdmin;
     45        WuiTmLink.__init__(self, sName = sName,
     46                           sUrlBase = WuiAdmin.ksScriptName,
     47                           dParams = { WuiAdmin.ksParamAction: WuiAdmin.ksActionFailureCategoryDetails,
     48                                       FailureCategoryData.ksParam_idFailureCategory: idFailureCategory, },
     49                           fBracketed = fBracketed);
     50        self.idFailureCategory = idFailureCategory;
     51
    3552
    3653
     
    7188        return True;
    7289
     90    def _generatePostFormContent(self, oData):
     91        """
     92        Adds a table with the category members below the form.
     93        """
     94        if oData.idFailureCategory is not None and oData.idFailureCategory >= 0:
     95            oLogic    = FailureReasonLogic(self._oDisp.getDb());
     96            tsNow     = self._oDisp.getNow();
     97            cMax      = 4096;
     98            aoEntries = oLogic.fetchForListingInCategory(0, cMax, tsNow, oData.idFailureCategory)
     99            if len(aoEntries) > 0:
     100                oList = WuiAdminFailureReasonList(aoEntries, 0, cMax, tsNow, fnDPrint = None, oDisp = self._oDisp);
     101                return [ [ 'Members', oList.show(fShowNavigation = False)[1]], ];
     102        return [];
     103
     104
    73105
    74106class WuiFailureCategoryList(WuiListContentBase):
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuiadminfailurereason.py

    r61220 r61250  
    3232# Validation Kit imports.
    3333from testmanager.webui.wuibase        import WuiException
    34 from testmanager.webui.wuicontentbase import WuiFormContentBase, WuiListContentBase, WuiTmLink
    35 from testmanager.core.failurereason   import FailureReasonData
    36 from testmanager.core.failurecategory import FailureCategoryLogic
    37 from testmanager.core.db              import TMDatabaseConnection
     34from testmanager.webui.wuicontentbase import WuiFormContentBase, WuiListContentBase, WuiContentBase, WuiTmLink;
     35from testmanager.core.failurereason   import FailureReasonData;
     36from testmanager.core.failurecategory import FailureCategoryLogic;
     37from testmanager.core.db              import TMDatabaseConnection;
     38
     39
     40
     41class WuiFailureReasonDetailsLink(WuiTmLink):
     42    """ Short link to a failure reason. """
     43    def __init__(self, idFailureReason, sName = WuiContentBase.ksShortDetailsLink, sTitle = None, fBracketed = None):
     44        if fBracketed is None:
     45            fBracketed = len(sName) > 2;
     46        from testmanager.webui.wuiadmin import WuiAdmin;
     47        WuiTmLink.__init__(self, sName = sName,
     48                           sUrlBase = WuiAdmin.ksScriptName,
     49                           dParams = { WuiAdmin.ksParamAction: WuiAdmin.ksActionFailureReasonDetails,
     50                                       FailureReasonData.ksParam_idFailureReason: idFailureReason, },
     51                           fBracketed = fBracketed);
     52        self.idFailureReason = idFailureReason;
     53
     54
     55
     56class WuiFailureReasonAddLink(WuiTmLink):
     57    """ Link for adding a failure reason. """
     58    def __init__(self, sName = WuiContentBase.ksShortAddLink, sTitle = None, fBracketed = None):
     59        if fBracketed is None:
     60            fBracketed = len(sName) > 2;
     61        from testmanager.webui.wuiadmin import WuiAdmin;
     62        WuiTmLink.__init__(self, sName = sName,
     63                           sUrlBase = WuiAdmin.ksScriptName,
     64                           dParams = { WuiAdmin.ksParamAction: WuiAdmin.ksActionFailureReasonAdd, },
     65                           fBracketed = fBracketed);
     66
    3867
    3968
     
    107136
    108137    def _formatListEntry(self, iEntry):
    109         from testmanager.webui.wuiadmin import WuiAdmin
     138        from testmanager.webui.wuiadmin                 import WuiAdmin
     139        from testmanager.webui.wuiadminfailurecategory  import WuiFailureReasonCategoryLink;
    110140        oEntry = self._aoEntries[iEntry]
    111141
    112142        return [ oEntry.idFailureReason,
    113                  oEntry.idFailureCategory,
     143                 WuiFailureReasonCategoryLink(oEntry.idFailureCategory, sName = oEntry.oCategory.sShort, fBracketed = False),
    114144                 oEntry.sShort,
    115145                 oEntry.sFull,
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuibase.py

    r61239 r61250  
    104104        self._oSrvGlue          = oSrvGlue;
    105105        self._oDb               = TMDatabaseConnection(self.dprint if config.g_kfWebUiSqlDebug else None, oSrvGlue = oSrvGlue);
     106        self._tsNow             = None;  # Set by getEffectiveDateParam.
    106107        self._asCheckedParams   = [];
    107108        self._dParams           = None;  # Set by dispatchRequest.
     
    303304        return self._oDb;
    304305
     306    def getNow(self):
     307        """
     308        Returns the effective date.
     309        """
     310        return self._tsNow;
     311
    305312
    306313    #
     
    506513        return aoListOfTestCases
    507514
    508     def getEffectiveDateParam(self, sParamName=None):
     515    def getEffectiveDateParam(self, sParamName = None):
    509516        """
    510517        Gets the effective date parameter.
     518
    511519        Returns a timestamp suitable for database and url parameters.
    512520        Returns None if not found or empty.
     521
     522        The first call with sParamName set to None will set the internal _tsNow
     523        value upon successfull return.
    513524        """
    514525
     
    535546            if sError is not None:
    536547                raise WuiException('%s parameter "%s" ("%s") is invalid: %s' % (self._sAction, sName, sValue, sError));
     548            if sParamName is None and self._tsNow is None:
     549                self._tsNow = sValue;
    537550            return sValue;
    538551
     
    555568        oDate = self._oDb.fetchOne()[0];
    556569
    557         return str(oDate);
     570        sValue = str(oDate);
     571        if sParamName is None and self._tsNow is None:
     572            self._tsNow = sValue;
     573        return sValue;
    558574
    559575    def getRedirectToParameter(self, sDefault = None):
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuicontentbase.py

    r61223 r61250  
    345345        _ = oForm; _ = oData;
    346346        raise Exception('Reimplement me!');
     347
     348    def _generatePostFormContent(self, oData):
     349        """
     350        Generate optional content that comes below the form.
     351        Returns a list of tuples, where the first tuple element is the title
     352        and the second the content.  I.e. similar to show() output.
     353        """
     354        _ = oData;
     355        return [];
    347356
    348357    def _calcChangeLogEntryLinks(self, aoEntries, iEntry):
     
    522531        return sContent;
    523532
     533    def _generateTopRowFormActions(self, oData):
     534        """
     535        Returns a list of WuiTmLinks.
     536        """
     537        aoActions = [];
     538        if self._sMode == self.ksMode_Show and self._fEditable:
     539            # Remove _idGen and effective date since we're always editing the current data,
     540            # and make sure the primary ID is present.
     541            dParams = self._oDisp.getParameters();
     542            if hasattr(oData, 'ksIdGenAttr'):
     543                sIdGenParam = getattr(oData, 'ksParam_' + oData.ksIdGenAttr);
     544                if sIdGenParam in dParams:
     545                    del dParams[sIdGenParam];
     546            if WuiDispatcherBase.ksParamEffectiveDate in dParams:
     547                del dParams[WuiDispatcherBase.ksParamEffectiveDate];
     548            dParams[getattr(oData, 'ksParam_' + oData.ksIdAttr)] = getattr(oData, oData.ksIdAttr);
     549
     550            dParams[WuiDispatcherBase.ksParamAction] = getattr(self._oDisp, self._sActionBase + 'Edit');
     551            aoActions.append(WuiTmLink('Edit', '', dParams));
     552
     553            # Add clone operation if available. This uses the same data selection as for showing details.
     554            if hasattr(self._oDisp, self._sActionBase + 'Clone'):
     555                dParams = self._oDisp.getParameters();
     556                dParams[WuiDispatcherBase.ksParamAction] = getattr(self._oDisp, self._sActionBase + 'Clone');
     557                aoActions.append(WuiTmLink('Clone', '', dParams));
     558
     559        elif self._sMode == self.ksMode_Edit:
     560            # Details views the details at a given time, so we need either idGen or an effecive date + regular id.
     561            dParams = {};
     562            if hasattr(oData, 'ksIdGenAttr'):
     563                sIdGenParam = getattr(oData, 'ksParam_' + oData.ksIdGenAttr);
     564                dParams[sIdGenParam] = getattr(oData, oData.ksIdGenAttr);
     565            elif hasattr(oData, 'tsEffective'):
     566                dParams[WuiDispatcherBase.ksParamEffectiveDate] = oData.tsEffective;
     567                dParams[getattr(oData, 'ksParam_' + oData.ksIdAttr)] = getattr(oData, oData.ksIdAttr);
     568            dParams[WuiDispatcherBase.ksParamAction] = getattr(self._oDisp, self._sActionBase + 'Details');
     569            aoActions.append(WuiTmLink('Details', '', dParams));
     570
     571        return aoActions;
     572
    524573    def showForm(self, dErrors = None, sErrorMsg = None):
    525574        """
     
    544593            sContent = oForm.finalize();
    545594
     595        # Add any post form content.
     596        atPostFormContent = self._generatePostFormContent(self._oData);
     597        if atPostFormContent is not None and len(atPostFormContent) > 0:
     598            for iSection, tSection in enumerate(atPostFormContent):
     599                (sSectionTitle, sSectionContent) = tSection;
     600                sContent += u'<div id="postform-%d"  class="tmformpostsection">\n' % (iSection,);
     601                if sSectionTitle is not None and len(sSectionTitle) > 0:
     602                    sContent += '<h3 class="tmformpostheader">%s</h3>\n' % (webutils.escapeElem(sSectionTitle),);
     603                sContent += u' <div id="postform-%d-content" class="tmformpostcontent">\n' % (iSection,);
     604                sContent += sSectionContent;
     605                sContent += u' </div>\n' \
     606                            u'</div>\n';
     607
    546608        # Add action to the top.
    547         aoActions = [];
    548         if self._sMode == self.ksMode_Show and self._fEditable:
    549             # Remove _idGen and effective date since we're always editing the current data,
    550             # and make sure the primary ID is present.
    551             dParams = self._oDisp.getParameters();
    552             if hasattr(self._oData, 'ksIdGenAttr'):
    553                 sIdGenParam = getattr(self._oData, 'ksParam_' + self._oData.ksIdGenAttr);
    554                 if sIdGenParam in dParams:
    555                     del dParams[sIdGenParam];
    556             if WuiDispatcherBase.ksParamEffectiveDate in dParams:
    557                 del dParams[WuiDispatcherBase.ksParamEffectiveDate];
    558             dParams[getattr(self._oData, 'ksParam_' + self._oData.ksIdAttr)] = getattr(self._oData, self._oData.ksIdAttr);
    559 
    560             dParams[WuiDispatcherBase.ksParamAction] = getattr(self._oDisp, self._sActionBase + 'Edit');
    561             aoActions.append(WuiTmLink('Edit', '', dParams));
    562 
    563             # Add clone operation if available. This uses the same data selection as for showing details.
    564             if hasattr(self._oDisp, self._sActionBase + 'Clone'):
    565                 dParams = self._oDisp.getParameters();
    566                 dParams[WuiDispatcherBase.ksParamAction] = getattr(self._oDisp, self._sActionBase + 'Clone');
    567                 aoActions.append(WuiTmLink('Clone', '', dParams));
    568 
    569         elif self._sMode == self.ksMode_Edit:
    570             # Details views the details at a given time, so we need either idGen or an effecive date + regular id.
    571             dParams = {};
    572             if hasattr(self._oData, 'ksIdGenAttr'):
    573                 sIdGenParam = getattr(self._oData, 'ksParam_' + self._oData.ksIdGenAttr);
    574                 dParams[sIdGenParam] = getattr(self._oData, self._oData.ksIdGenAttr);
    575             elif hasattr(self._oData, 'tsEffective'):
    576                 dParams[WuiDispatcherBase.ksParamEffectiveDate] = self._oData.tsEffective;
    577                 dParams[getattr(self._oData, 'ksParam_' + self._oData.ksIdAttr)] = getattr(self._oData, self._oData.ksIdAttr);
    578             dParams[WuiDispatcherBase.ksParamAction] = getattr(self._oDisp, self._sActionBase + 'Details');
    579             aoActions.append(WuiTmLink('Details', '', dParams));
    580 
     609        aoActions = self._generateTopRowFormActions(self._oData);
    581610        if len(aoActions) > 0:
    582611            sActionLinks = '<p>%s</p>' % (' '.join(unicode(oLink) for oLink in aoActions));
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuihlpform.py

    r61225 r61250  
    124124    # Non-input stuff.
    125125    #
    126     def addNonText(self, sValue, sLabel, sPostHtml = ''):
     126    def addNonText(self, sValue, sLabel, sName = 'non-text', sPostHtml = ''):
    127127        """Adds a read-only text input."""
    128         self._addLabel('non-text', sLabel, 'string');
     128        self._addLabel(sName, sLabel, 'string');
    129129        if sValue is None: sValue = '';
    130         return self._add(u'          <p>%s</p>%s\n'
     130        return self._add(u'          <p>%s%s</p>\n'
    131131                         u'        </div></div>\n'
    132132                         u'      </li>\n'
    133133                         % (escapeElem(unicode(sValue)), sPostHtml ));
     134
     135    def addRawHtml(self, sRawHtml, sLabel, sName = 'raw-html'):
     136        """Adds a read-only text input."""
     137        self._addLabel(sName, sLabel, 'string');
     138        self._add(sRawHtml);
     139        return self._add(u'        </div></div>\n'
     140                         u'      </li>\n');
    134141
    135142
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuimain.py

    r61239 r61250  
    3636from testmanager.webui.wuicontentbase       import WuiTmLink;
    3737from testmanager.core.report                import ReportLazyModel, ReportGraphModel, ReportModelBase;
    38 from testmanager.core.testresults           import TestResultLogic, TestResultFileDataEx;
     38from testmanager.core.testresults           import TestResultLogic, TestResultFileDataEx, TestResultData;
    3939from testmanager.core.base                  import TMExceptionBase, TMTooManyRows;
    4040from testmanager.core.testset               import TestSetData, TestSetLogic;
     
    6868    ksActionResultsGroupedByTestBox     = 'ResultsGroupedByTestBox'
    6969    ksActionResultsGroupedByTestCase    = 'ResultsGroupedByTestCase'
    70     ksActionTestResultDetails           = 'TestResultDetails'
     70    ksActionTestSetDetails              = 'TestSetDetails';
     71    ksActionTestResultDetails           = ksActionTestSetDetails;
     72    ksActionTestSetDetailsFromResult    = 'TestSetDetailsFromResult'
    7173    ksActionTestResultFailureDetails    = 'TestResultFailureDetails'
    7274    ksActionTestResultFailureAdd        = 'TestResultFailureAdd'
     
    162164    ## Test result period values.
    163165    kaoResultPeriods = [
    164         ( '1 hour',   'One hour',    1 ),
    165         ( '2 hours',  'Two hours',   2 ),
    166         ( '3 hours',  'Three hours', 3 ),
    167         ( '6 hours',  'Six hours',   6 ),
     166        ( '1 hour',   '1 hour',      1 ),
     167        ( '2 hours',  '2 hours',     2 ),
     168        ( '3 hours',  '3 hours',    3 ),
     169        ( '6 hours',  '6 hours',     6 ),
    168170        ( '12 hours', '12 hours',    12 ),
    169171
    170         ( '1 day',    'One day',     24 ),
    171         ( '2 days',   'Two days',    48 ),
    172         ( '3 days',   'Three days',  72 ),
    173 
    174         ( '1 week',   'One week',    168 ),
    175         ( '2 weeks',  'Two weeks',   336 ),
    176         ( '3 weeks',  'Three weeks', 504 ),
    177 
    178         ( '1 month',  'One month',   31 * 24 ),                             # The approx hour count varies with the start date.
    179         ( '2 months', 'Two month',   (31 + 31) * 24 ),                      # Using maximum values.
    180         ( '3 months', 'Three month', (31 + 30 + 31) * 24 ),
    181 
    182         ( '6 months', 'Six month',   (31 + 31 + 30 + 31 + 30 + 31) * 24 ),
    183 
    184         ( '1 year',   'One year',    365 * 24 ),
     172        ( '1 day',    '1 day',       24 ),
     173        ( '2 days',   '2 days',      48 ),
     174        ( '3 days',   '3 days',      72 ),
     175
     176        ( '1 week',   '1 week',      168 ),
     177        ( '2 weeks',  '2 weeks',     336 ),
     178        ( '3 weeks',  '3 weeks',    504 ),
     179
     180        ( '1 month',  '1 month',     31 * 24 ),                             # The approx hour count varies with the start date.
     181        ( '2 months', '2 months',    (31 + 31) * 24 ),                      # Using maximum values.
     182        ( '3 months', '3 months',    (31 + 30 + 31) * 24 ),
     183
     184        ( '6 months', '6 months',    (31 + 31 + 30 + 31 + 30 + 31) * 24 ),
     185
     186        ( '1 year',   '1 year',      365 * 24 ),
    185187    ];
    186188    ## The default test result period.
     
    202204
    203205        from testmanager.webui.wuitestresult import WuiGroupedResultList;
    204         #d[self.ksActionResultsUnGrouped]          = lambda: self._actionResultsListing(TestResultLogic, WuiGroupedResultList)
    205         d[self.ksActionResultsUnGrouped]          = lambda: self._actionGroupedResultsListing(
    206                                                                 TestResultLogic.ksResultsGroupingTypeNone,
    207                                                                 TestResultLogic,
     206        #d[self.ksActionResultsUnGrouped]            = lambda: self._actionResultsListing(TestResultLogic, WuiGroupedResultList)
     207        d[self.ksActionResultsUnGrouped]            = lambda: self._actionGroupedResultsListing(
     208                                                                  TestResultLogic.ksResultsGroupingTypeNone,
     209                                                                  TestResultLogic,
     210                                                                  WuiGroupedResultList)
     211
     212        d[self.ksActionResultsGroupedByTestGroup]   = lambda: self._actionGroupedResultsListing(
     213                                                                  TestResultLogic.ksResultsGroupingTypeTestGroup,
     214                                                                  TestResultLogic,
     215                                                                  WuiGroupedResultList)
     216
     217        d[self.ksActionResultsGroupedByBuildRev]    = lambda: self._actionGroupedResultsListing(
     218                                                                  TestResultLogic.ksResultsGroupingTypeBuildRev,
     219                                                                  TestResultLogic,
     220                                                                  WuiGroupedResultList)
     221
     222        d[self.ksActionResultsGroupedByTestBox]     = lambda: self._actionGroupedResultsListing(
     223                                                                  TestResultLogic.ksResultsGroupingTypeTestBox,
     224                                                                  TestResultLogic,
    208225                                                                WuiGroupedResultList)
    209226
    210         d[self.ksActionResultsGroupedByTestGroup] = lambda: self._actionGroupedResultsListing(
    211                                                                 TestResultLogic.ksResultsGroupingTypeTestGroup,
    212                                                                 TestResultLogic,
    213                                                                 WuiGroupedResultList)
    214 
    215         d[self.ksActionResultsGroupedByBuildRev]  = lambda: self._actionGroupedResultsListing(
    216                                                                 TestResultLogic.ksResultsGroupingTypeBuildRev,
    217                                                                 TestResultLogic,
    218                                                                 WuiGroupedResultList)
    219 
    220         d[self.ksActionResultsGroupedByTestBox]   = lambda: self._actionGroupedResultsListing(
    221                                                                 TestResultLogic.ksResultsGroupingTypeTestBox,
    222                                                                 TestResultLogic,
    223                                                                 WuiGroupedResultList)
    224 
    225         d[self.ksActionResultsGroupedByTestCase]   = lambda: self._actionGroupedResultsListing(
    226                                                                 TestResultLogic.ksResultsGroupingTypeTestCase,
    227                                                                 TestResultLogic,
    228                                                                 WuiGroupedResultList)
    229 
    230         d[self.ksActionResultsGroupedBySchedGroup] = lambda: self._actionGroupedResultsListing(
    231                                                                 TestResultLogic.ksResultsGroupingTypeSchedGroup,
    232                                                                 TestResultLogic,
    233                                                                 WuiGroupedResultList)
    234 
    235         d[self.ksActionTestResultDetails]          = self._actionTestResultDetails;
    236 
    237         d[self.ksActionTestResultFailureAdd]       = self._actionTestResultFailureAdd;
    238         d[self.ksActionTestResultFailureAddPost]   = self._actionTestResultFailureAddPost;
    239         d[self.ksActionTestResultFailureDetails]   = self._actionTestResultFailureDetails;
    240         d[self.ksActionTestResultFailureEdit]      = self._actionTestResultFailureEdit;
    241         d[self.ksActionTestResultFailureEditPost]  = self._actionTestResultFailureEditPost;
    242 
    243         d[self.ksActionViewLog]                 = self.actionViewLog;
    244         d[self.ksActionGetFile]                 = self.actionGetFile;
     227        d[self.ksActionResultsGroupedByTestCase]    = lambda: self._actionGroupedResultsListing(
     228                                                                 TestResultLogic.ksResultsGroupingTypeTestCase,
     229                                                                 TestResultLogic,
     230                                                                 WuiGroupedResultList)
     231
     232        d[self.ksActionResultsGroupedBySchedGroup]  = lambda: self._actionGroupedResultsListing(
     233                                                                 TestResultLogic.ksResultsGroupingTypeSchedGroup,
     234                                                                 TestResultLogic,
     235                                                                 WuiGroupedResultList)
     236
     237        d[self.ksActionTestSetDetails]              = self._actionTestSetDetails;
     238        d[self.ksActionTestSetDetailsFromResult]    = self._actionTestSetDetailsFromResult;
     239
     240        d[self.ksActionTestResultFailureAdd]        = self._actionTestResultFailureAdd;
     241        d[self.ksActionTestResultFailureAddPost]    = self._actionTestResultFailureAddPost;
     242        d[self.ksActionTestResultFailureDetails]    = self._actionTestResultFailureDetails;
     243        d[self.ksActionTestResultFailureEdit]       = self._actionTestResultFailureEdit;
     244        d[self.ksActionTestResultFailureEditPost]   = self._actionTestResultFailureEditPost;
     245
     246        d[self.ksActionViewLog]                     = self.actionViewLog;
     247        d[self.ksActionGetFile]                     = self.actionGetFile;
    245248        from testmanager.webui.wuireport import WuiReportSummary, WuiReportSuccessRate, WuiReportFailureReasons;
    246         d[self.ksActionReportSummary]           = lambda: self._actionGenericReport(ReportLazyModel, WuiReportSummary);
    247         d[self.ksActionReportRate]              = lambda: self._actionGenericReport(ReportLazyModel, WuiReportSuccessRate);
    248         d[self.ksActionReportFailureReasons]    = lambda: self._actionGenericReport(ReportLazyModel, WuiReportFailureReasons);
    249         d[self.ksActionGraphWiz]                = self._actionGraphWiz;
    250         d[self.ksActionVcsHistoryTooltip]       = self._actionVcsHistoryTooltip;
     249        d[self.ksActionReportSummary]               = lambda: self._actionGenericReport(ReportLazyModel, WuiReportSummary);
     250        d[self.ksActionReportRate]                  = lambda: self._actionGenericReport(ReportLazyModel, WuiReportSuccessRate);
     251        d[self.ksActionReportFailureReasons]        = lambda: self._actionGenericReport(ReportLazyModel, WuiReportFailureReasons);
     252        d[self.ksActionGraphWiz]                    = self._actionGraphWiz;
     253        d[self.ksActionVcsHistoryTooltip]           = self._actionVcsHistoryTooltip;
     254
     255        # Legacy.
     256        d['TestResultDetails']                      = d[self.ksActionTestSetDetails];
    251257
    252258
     
    389395            ('+0000-00-00 00:00:00.00', 'Now', ' title="Present Day. Present Time."'), # lain :)
    390396
    391             ('-0000-00-00 01:00:00.00', 'One hour ago', ''),
    392             ('-0000-00-00 02:00:00.00', 'Two hours ago', ''),
    393             ('-0000-00-00 03:00:00.00', 'Three hours ago', ''),
    394 
    395             ('-0000-00-01 00:00:00.00', 'One day ago', ''),
    396             ('-0000-00-02 00:00:00.00', 'Two days ago', ''),
    397             ('-0000-00-03 00:00:00.00', 'Three days ago', ''),
    398 
    399             ('-0000-00-07 00:00:00.00', 'One week ago', ''),
    400             ('-0000-00-14 00:00:00.00', 'Two weeks ago', ''),
    401             ('-0000-00-21 00:00:00.00', 'Three weeks ago', ''),
    402 
    403             ('-0000-01-00 00:00:00.00', 'One month ago', ''),
    404             ('-0000-02-00 00:00:00.00', 'Two months ago', ''),
    405             ('-0000-03-00 00:00:00.00', 'Three months ago', ''),
    406             ('-0000-04-00 00:00:00.00', 'Four months ago', ''),
    407             ('-0000-05-00 00:00:00.00', 'Five months ago', ''),
     397            ('-0000-00-00 01:00:00.00', '1 hour ago', ''),
     398            ('-0000-00-00 02:00:00.00', '2 hours ago', ''),
     399            ('-0000-00-00 03:00:00.00', '3 hours ago', ''),
     400
     401            ('-0000-00-01 00:00:00.00', '1 day ago', ''),
     402            ('-0000-00-02 00:00:00.00', '2 days ago', ''),
     403            ('-0000-00-03 00:00:00.00', '3 days ago', ''),
     404
     405            ('-0000-00-07 00:00:00.00', '1 week ago', ''),
     406            ('-0000-00-14 00:00:00.00', '2 weeks ago', ''),
     407            ('-0000-00-21 00:00:00.00', '3 weeks ago', ''),
     408
     409            ('-0000-01-00 00:00:00.00', '1 month ago', ''),
     410            ('-0000-02-00 00:00:00.00', '2 months ago', ''),
     411            ('-0000-03-00 00:00:00.00', '3 months ago', ''),
     412            ('-0000-04-00 00:00:00.00', '4 months ago', ''),
     413            ('-0000-05-00 00:00:00.00', '5 months ago', ''),
    408414            ('-0000-06-00 00:00:00.00', 'Half a year ago', ''),
    409415
    410             ('-0001-00-00 00:00:00.00', 'One year ago', ''),
     416            ('-0001-00-00 00:00:00.00', '1 year ago', ''),
    411417        ]
    412418        fSelected = False;
     
    842848        return WuiDispatcherBase._generatePage(self)
    843849
    844     def _actionTestResultDetails(self):
     850    def _actionTestSetDetailsCommon(self, idTestSet):
    845851        """Show test case execution result details."""
    846852        from testmanager.webui.wuitestresult import WuiTestResult;
    847853
    848854        self._sTemplate = 'template-details.html';
    849         idTestSet = self.getIntParam(TestSetData.ksParam_idTestSet);
    850855        self._checkForUnknownParameters()
    851856
     
    878883        return True
    879884
     885    def _actionTestSetDetails(self):
     886        """Show test case execution result details."""
     887        idTestSet = self.getIntParam(TestSetData.ksParam_idTestSet);
     888        return self._actionTestSetDetailsCommon(idTestSet);
     889
     890    def _actionTestSetDetailsFromResult(self):
     891        """Show test case execution result details."""
     892        idTestResult = self.getIntParam(TestSetData.ksParam_idTestResult);
     893        oTestResultData = TestResultData().initFromDbWithId(self._oDb, idTestResult);
     894        return self._actionTestSetDetailsCommon(oTestResultData.idTestSet);
     895
     896
    880897    def _actionTestResultFailureAdd(self):
    881898        """ Pro forma. """
     
    912929        from testmanager.core.testresults import TestResultFailureLogic, TestResultFailureData;
    913930        from testmanager.webui.wuitestresultfailure import WuiTestResultFailure;
    914         if self.ksParamRedirectTo not in self._dParams:
    915             raise WuiException('Missing parameter ' + self.ksParamRedirectTo);
    916 
    917931        return self._actionGenericFormEditPost(TestResultFailureData, TestResultFailureLogic,
    918932                                               WuiTestResultFailure, self.ksActionResultsUnGrouped);
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuitestresult.py

    r61238 r61250  
    3232
    3333# Validation Kit imports.
    34 from testmanager.webui.wuicontentbase   import WuiContentBase, WuiListContentBase, WuiHtmlBase, WuiTmLink, WuiLinkBase, \
    35                                                WuiSvnLink, WuiSvnLinkWithTooltip, WuiBuildLogLink, WuiRawHtml;
    36 from testmanager.webui.wuimain          import WuiMain;
    37 from testmanager.webui.wuihlpform       import WuiHlpForm;
    38 from testmanager.core.failurereason     import FailureReasonData, FailureReasonLogic;
    39 from testmanager.core.report            import ReportGraphModel;
    40 from testmanager.core.testbox           import TestBoxData;
    41 from testmanager.core.testcase          import TestCaseData;
    42 from testmanager.core.testset           import TestSetData;
    43 from testmanager.core.testgroup         import TestGroupData;
    44 from testmanager.core.testresults       import TestResultFailureData;
    45 from testmanager.core.build             import BuildData;
    46 from testmanager.core                   import db;
    47 from testmanager                        import config;
    48 from common                             import webutils, utils;
    49 
    50 
    51 class WuiFailureReasonDetailsLink(WuiTmLink):
    52     """ Short link to a failure reason. """
    53     def __init__(self, idFailureReason, sName = WuiContentBase.ksShortDetailsLink, sTitle = None, fBracketed = None):
    54         if fBracketed is None:
    55             fBracketed = len(sName) > 2;
    56         from testmanager.webui.wuiadmin import WuiAdmin;
    57         WuiTmLink.__init__(self, sName = sName,
    58                            sUrlBase = WuiAdmin.ksScriptName,
    59                            dParams = { WuiAdmin.ksParamAction: WuiAdmin.ksActionFailureReasonDetails,
    60                                        FailureReasonData.ksParam_idFailureReason: idFailureReason, },
    61                            fBracketed = fBracketed);
    62         self.idFailureReason = idFailureReason;
    63 
    64 class WuiFailureReasonAddLink(WuiTmLink):
    65     """ Link for adding a failure reason. """
    66     def __init__(self, sName = WuiContentBase.ksShortAddLink, sTitle = None, fBracketed = None):
    67         if fBracketed is None:
    68             fBracketed = len(sName) > 2;
    69         from testmanager.webui.wuiadmin import WuiAdmin;
    70         WuiTmLink.__init__(self, sName = sName,
    71                            sUrlBase = WuiAdmin.ksScriptName,
    72                            dParams = { WuiAdmin.ksParamAction: WuiAdmin.ksActionFailureReasonAdd, },
    73                            fBracketed = fBracketed);
     34from testmanager.webui.wuicontentbase           import WuiContentBase, WuiListContentBase, WuiHtmlBase, WuiTmLink, WuiLinkBase, \
     35                                                       WuiSvnLink, WuiSvnLinkWithTooltip, WuiBuildLogLink, WuiRawHtml;
     36from testmanager.webui.wuimain                  import WuiMain;
     37from testmanager.webui.wuihlpform               import WuiHlpForm;
     38from testmanager.webui.wuiadminfailurereason    import WuiFailureReasonAddLink, WuiFailureReasonDetailsLink;
     39from testmanager.webui.wuitestresultfailure     import WuiTestResultFailureDetailsLink;
     40from testmanager.core.failurereason             import FailureReasonData, FailureReasonLogic;
     41from testmanager.core.report                    import ReportGraphModel;
     42from testmanager.core.testbox                   import TestBoxData;
     43from testmanager.core.testcase                  import TestCaseData;
     44from testmanager.core.testset                   import TestSetData;
     45from testmanager.core.testgroup                 import TestGroupData;
     46from testmanager.core.testresults               import TestResultFailureData;
     47from testmanager.core.build                     import BuildData;
     48from testmanager.core                           import db;
     49from testmanager                                import config;
     50from common                                     import webutils, utils;
     51
    7452
    7553
     
    401379                oForm.addComboBox(TestResultFailureData.ksParam_idFailureReason, oData.idFailureReason, 'Reason',
    402380                                  aoFailureReasons,
    403                                   sPostHtml = WuiFailureReasonDetailsLink(oData.idFailureReason).toHtml());
     381                                  sPostHtml = u' ' + WuiFailureReasonDetailsLink(oData.idFailureReason).toHtml()
     382                                            + u' ' + WuiFailureReasonAddLink('New', fBracketed = False).toHtml());
    404383                oForm.addMultilineText(TestResultFailureData.ksParam_sComment, oData.sComment, 'Comment')
    405384
    406                 oForm.addNonText('%s (%s), %s' % (oData.oAuthor.sUsername, oData.oAuthor.sUsername, self.formatTsShort(oData.tsEffective)), 'Sheriff');
     385                oForm.addNonText(u'%s (%s), %s'
     386                                 % ( oData.oAuthor.sUsername, oData.oAuthor.sUsername,
     387                                     self.formatTsShort(oData.tsEffective),),
     388                                 'Sheriff',
     389                                 sPostHtml = ' ' + WuiTestResultFailureDetailsLink(oData.idTestResult, "Show Details").toHtml() )
     390
    407391                oForm.addTextHidden(TestResultFailureData.ksParam_tsEffective, oData.tsEffective);
    408392                oForm.addTextHidden(TestResultFailureData.ksParam_tsExpire, oData.tsExpire);
    409393                oForm.addTextHidden(TestResultFailureData.ksParam_uidAuthor, oData.uidAuthor);
     394                oForm.addSubmit('Change Reason');
     395
    410396            else:
    411397                oForm.addComboBox(TestResultFailureData.ksParam_idFailureReason, -1, 'Reason', aoFailureReasons,
     
    415401                oForm.addTextHidden(TestResultFailureData.ksParam_tsExpire, '');
    416402                oForm.addTextHidden(TestResultFailureData.ksParam_uidAuthor, '');
    417 
    418             oForm.addSubmit('Change Reason');
     403                oForm.addSubmit('Add Reason');
     404
    419405            sHtml += oForm.finalize();
    420406        return sHtml;
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuitestresultfailure.py

    r61217 r61250  
    3030
    3131# Validation Kit imports.
    32 from testmanager.webui.wuicontentbase   import WuiFormContentBase;
    33 from testmanager.core.testresults       import TestResultFailureData;
    34 from testmanager.core.failurereason     import FailureReasonLogic;
     32from testmanager.webui.wuicontentbase           import WuiFormContentBase, WuiTmLink;
     33from testmanager.webui.wuimain                  import WuiMain;
     34from testmanager.webui.wuiadminfailurereason    import WuiFailureReasonDetailsLink, WuiFailureReasonAddLink;
     35from testmanager.core.testresults               import TestResultFailureData;
     36from testmanager.core.testset                   import TestSetData;
     37from testmanager.core.failurereason             import FailureReasonLogic;
     38
     39
     40
     41class WuiTestResultFailureDetailsLink(WuiTmLink):
     42    """ Link for adding a failure reason. """
     43    def __init__(self, idTestResult, sName = u'\u2397', sTitle = None, fBracketed = None):
     44        if fBracketed is None:
     45            fBracketed = len(sName) > 2;
     46        WuiTmLink.__init__(self, sName = sName,
     47                           sUrlBase = WuiMain.ksScriptName,
     48                           dParams = { WuiMain.ksParamAction: WuiMain.ksActionTestResultFailureDetails,
     49                                       TestResultFailureData.ksParam_idTestResult: idTestResult, },
     50                           fBracketed = fBracketed);
     51        self.idTestResult = idTestResult;
     52
    3553
    3654
     
    5371
    5472        aoFailureReasons = FailureReasonLogic(self._oDisp.getDb()).fetchForCombo('Todo: Figure out why');
     73        sPostHtml = '';
     74        if oData.idFailureReason is not None and oData.idFailureReason >= 0:
     75            sPostHtml += u' ' + WuiFailureReasonDetailsLink(oData.idFailureReason).toHtml();
     76        sPostHtml += u' ' + WuiFailureReasonAddLink('New', fBracketed = False).toHtml();
    5577        oForm.addComboBox(TestResultFailureData.ksParam_idFailureReason, oData.idFailureReason,
    56                           'Reason', aoFailureReasons)
     78                          'Reason', aoFailureReasons, sPostHtml = sPostHtml);
    5779        oForm.addMultilineText(TestResultFailureData.ksParam_sComment,   oData.sComment,     'Comment');
    5880        oForm.addIntRO(      TestResultFailureData.ksParam_idTestResult, oData.idTestResult, 'Test Result ID');
     
    6486        return True;
    6587
     88    def _generateTopRowFormActions(self, oData):
     89        """
     90        We add a way to get back to the test set to the actions.
     91        """
     92        aoActions = super(WuiTestResultFailure, self)._generateTopRowFormActions(oData);
     93        if oData and oData.idTestResult is not None and oData.idTestResult > 0:
     94            aoActions.append(WuiTmLink('Associated Test Set', WuiMain.ksScriptName,
     95                                       { WuiMain.ksParamAction: WuiMain.ksActionTestSetDetailsFromResult,
     96                                         TestSetData.ksParam_idTestResult: oData.idTestResult }
     97                                       ));
     98        return aoActions;
     99
     100
     101
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette