Changeset 658

Show
Ignore:
Timestamp:
06/25/08 19:30:36 (7 months ago)
Author:
dustin@v.igoro.us
Message:

#228:step-statistics.patch
Introduce steps statistics

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • buildbot/status/builder.py

    r653 r658  
    450450        del self.entries 
    451451 
    452  
    453452class HTMLLogFile: 
    454453    implements(interfaces.IStatusLog) 
     
    643642    L{buildbot.process.step.BuildStep}. 
    644643 
     644    Statistics contain any information gleaned from a step that is 
     645    not in the form of a logfile.  As an example, steps that run 
     646    tests might gather statistics about the number of passed, failed, 
     647    or skipped tests. 
     648 
    645649    @type color: string 
    646650    @cvar color: color that this step feels best represents its 
     
    656660    @type logs: dict of string -> L{buildbot.status.builder.LogFile} 
    657661    @ivar logs: logs of steps 
     662    @type statistics: dict 
     663    @ivar statistics: results from running this step 
    658664    """ 
    659665    # note that these are created when the Build is set up, before each 
    660666    # corresponding BuildStep has started. 
    661667    implements(interfaces.IBuildStepStatus, interfaces.IStatusEvent) 
    662     persistenceVersion = 1 
     668    persistenceVersion = 2 
    663669 
    664670    started = None 
     
    672678    updates = {} 
    673679    finishedWatchers = [] 
     680    statistics = {} 
    674681 
    675682    def __init__(self, parent): 
     
    681688        self.updates = {} 
    682689        self.finishedWatchers = [] 
     690        self.statistics = {} 
    683691 
    684692    def getName(self): 
     
    764772        """ 
    765773        return (self.results, self.text2) 
     774 
     775    def hasStatistic(self, name): 
     776        """Return true if this step has a value for the given statistic. 
     777        """ 
     778        return self.statistics.has_key(name) 
     779 
     780    def getStatistic(self, name, default=None): 
     781        """Return the given statistic, if present 
     782        """ 
     783        return self.statistics.get(name, default) 
    766784 
    767785    # subscription interface 
     
    848866        self.text2 = text 
    849867 
     868    def setStatistic(self, name, value): 
     869        """Set the given statistic.  Usually called by subclasses. 
     870        """ 
     871        self.statistics[name] = value 
     872 
    850873    def stepFinished(self, results): 
    851874        self.finished = util.now() 
     
    886909        if not hasattr(self, "urls"): 
    887910            self.urls = {} 
     911 
     912    def upgradeToVersion2(self): 
     913        if not hasattr(self, "statistics"): 
     914            self.statistics = {} 
    888915 
    889916 
     
    9781005    def getTimes(self): 
    9791006        return (self.started, self.finished) 
     1007 
     1008    _sentinel = [] # used as a sentinel to indicate unspecified initial_value 
     1009    def getSummaryStatistic(self, name, summary_fn, initial_value=_sentinel): 
     1010        """Summarize the named statistic over all steps in which it 
     1011        exists, using combination_fn and initial_value to combine multiple 
     1012        results into a single result.  This translates to a call to Python's 
     1013        X{reduce}:: 
     1014            return reduce(summary_fn, step_stats_list, initial_value) 
     1015        """ 
     1016        step_stats_list = [ 
     1017                st.getStatistic(name) 
     1018                for st in self.steps 
     1019                if st.hasStatistic(name) ] 
     1020        if initial_value is self._sentinel: 
     1021            return reduce(summary_fn, step_stats_list) 
     1022        else: 
     1023            return reduce(summary_fn, step_stats_list, initial_value) 
    9801024 
    9811025    def isFinished(self): 
  • buildbot/test/test_status.py

    r640 r658  
    22 
    33import email, os 
     4import operator 
    45 
    56from zope.interface import implements 
     
    11951196    def send(self, msg): 
    11961197        self.message += msg 
     1198 
     1199class StepStatistics(unittest.TestCase): 
     1200    def testStepStatistics(self): 
     1201        status = builder.BuildStatus(builder.BuilderStatus("test"), 123) 
     1202        status.addStepWithName('step1') 
     1203        status.addStepWithName('step2') 
     1204        status.addStepWithName('step3') 
     1205        status.addStepWithName('step4') 
     1206 
     1207        steps = status.getSteps() 
     1208        (step1, step2, step3, step4) = steps 
     1209 
     1210        step1.setStatistic('test-prop', 1) 
     1211        step3.setStatistic('test-prop', 2) 
     1212        step4.setStatistic('test-prop', 4) 
     1213 
     1214        step1.setStatistic('other-prop', 27) 
     1215        # Just to have some other properties around 
     1216 
     1217        self.failUnlessEqual(step1.getStatistic('test-prop'), 1, 
     1218            'Retrieve an existing property') 
     1219        self.failUnlessEqual(step1.getStatistic('test-prop', 99), 1, 
     1220            "Don't default an existing property") 
     1221        self.failUnlessEqual(step2.getStatistic('test-prop', 99), 99, 
     1222            'Default a non-existant property') 
     1223 
     1224        self.failUnlessEqual( 
     1225            status.getSummaryStatistic('test-prop', operator.add), 7, 
     1226            'Sum property across the build') 
     1227 
     1228        self.failUnlessEqual( 
     1229            status.getSummaryStatistic('test-prop', operator.add, 13), 20, 
     1230            'Sum property across the build with initial value')