⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 243342 in webkit


Ignore:
Timestamp:
Mar 21, 2019, 4:11:58 PM (7 years ago)
Author:
aakash_jain@apple.com
Message:

[ews-build] Retry API test in case of failures
https://bugs.webkit.org/show_bug.cgi?id=196004

Reviewed by Lucas Forschler.

  • BuildSlaveSupport/ews-build/steps.py:

(UnApplyPatchIfRequired.doStepIf): Updated doStepIf to include patchFailedAPITests.
(CompileWebKitToT.doStepIf): Ditto.
(RunAPITests.evaluateCommand): Check if tests failed and retry them if required.
(ReRunAPITests): Re-run API tests.
(ReRunAPITests.evaluateCommand): Check if tests failed and retry on clean build if required.
(RunAPITestsWithoutPatch): Run API tests without patch.
(RunAPITestsWithoutPatch.doStepIf):
(RunAPITestsWithoutPatch.hideStepIf):
(RunAPITestsWithoutPatch.evaluateCommand):
(AnalyzeAPITestsResults): Analyze API test results from previous runs.
(AnalyzeAPITestsResults.start):
(AnalyzeAPITestsResults.analyzeResults): Analyze API test results.
(AnalyzeAPITestsResults.getBuildStepByName): Search for a build step by name.
(AnalyzeAPITestsResults.getTestsResults): Get the test results from previous API tesst steps.

  • BuildSlaveSupport/ews-build/steps_unittest.py: Monkey patched FakeBuild.
Location:
trunk/Tools
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/BuildSlaveSupport/ews-build/steps.py

    r243217 r243342  
    2929from twisted.internet import defer
    3030
     31import json
    3132import re
    3233import requests
     
    377378
    378379    def doStepIf(self, step):
    379         return self.getProperty('patchFailedToBuild') or self.getProperty('patchFailedJSCTests')
     380        return self.getProperty('patchFailedToBuild') or self.getProperty('patchFailedJSCTests') or self.getProperty('patchFailedAPITests')
    380381
    381382    def hideStepIf(self, results, step):
     
    527528
    528529    def doStepIf(self, step):
    529         return self.getProperty('patchFailedToBuild')
     530        return self.getProperty('patchFailedToBuild') or self.getProperty('patchFailedAPITests')
    530531
    531532    def hideStepIf(self, results, step):
     
    711712        return int(match.group('ran')) - int(match.group('passed'))
    712713
     714    def evaluateCommand(self, cmd):
     715        rc = super(RunAPITests, self).evaluateCommand(cmd)
     716        if rc == SUCCESS:
     717            message = 'Passed API tests'
     718            self.descriptionDone = message
     719            self.build.results = SUCCESS
     720            self.build.buildFinished([message], SUCCESS)
     721        else:
     722            self.build.addStepsAfterCurrentStep([ReRunAPITests()])
     723        return rc
     724
     725
     726class ReRunAPITests(RunAPITests):
     727    name = 're-run-api-tests'
     728
     729    def evaluateCommand(self, cmd):
     730        rc = TestWithFailureCount.evaluateCommand(self, cmd)
     731        if rc == SUCCESS:
     732            message = 'Passed API tests'
     733            self.descriptionDone = message
     734            self.build.results = SUCCESS
     735            self.build.buildFinished([message], SUCCESS)
     736        else:
     737            self.setProperty('patchFailedAPITests', True)
     738            self.build.addStepsAfterCurrentStep([UnApplyPatchIfRequired(), CompileWebKitToT(), RunAPITestsWithoutPatch(), AnalyzeAPITestsResults()])
     739        return rc
     740
     741
     742class RunAPITestsWithoutPatch(RunAPITests):
     743    name = 'run-api-tests-without-patch'
     744
     745    def evaluateCommand(self, cmd):
     746        return TestWithFailureCount.evaluateCommand(self, cmd)
     747
     748
     749class AnalyzeAPITestsResults(buildstep.BuildStep):
     750    name = 'analyze-api-tests-results'
     751    description = ['analyze-api-test-results']
     752    descriptionDone = ['analyze-api-tests-results']
     753
     754    def start(self):
     755        self.results = {}
     756        d = self.getTestsResults(RunAPITests.name)
     757        d.addCallback(lambda res: self.getTestsResults(ReRunAPITests.name))
     758        d.addCallback(lambda res: self.getTestsResults(RunAPITestsWithoutPatch.name))
     759        d.addCallback(lambda res: self.analyzeResults())
     760        return defer.succeed(None)
     761
     762    def analyzeResults(self):
     763        if not self.results or len(self.results) == 0:
     764            self._addToLog('stderr', 'Unable to parse API test results: {}'.format(self.results))
     765            self.finished(RETRY)
     766            self.build.buildFinished(['Unable to parse API test results'], RETRY)
     767            return -1
     768
     769        first_run_results = self.results.get(RunAPITests.name)
     770        second_run_results = self.results.get(ReRunAPITests.name)
     771        clean_tree_results = self.results.get(RunAPITestsWithoutPatch.name)
     772
     773        if not (first_run_results and second_run_results and clean_tree_results):
     774            self.finished(RETRY)
     775            self.build.buildFinished(['Unable to parse API test results'], RETRY)
     776            return -1
     777
     778        def getAPITestFailures(result):
     779            # TODO: Analyze Time-out, Crash and Failure independently
     780            return set([failure.get('name') for failure in result.get('Timedout', [])] +
     781                [failure.get('name') for failure in result.get('Crashed', [])] +
     782                [failure.get('name') for failure in result.get('Failed', [])])
     783
     784        first_run_failures = getAPITestFailures(first_run_results)
     785        second_run_failures = getAPITestFailures(second_run_results)
     786        clean_tree_failures = getAPITestFailures(clean_tree_results)
     787
     788        self._addToLog('stderr', '\nFailures in API Test first run: {}'.format(first_run_failures))
     789        self._addToLog('stderr', '\nFailures in API Test second run: {}'.format(first_run_failures))
     790        self._addToLog('stderr', '\nFailures in API Test on clean tree: {}'.format(clean_tree_failures))
     791        failures_with_patch = first_run_failures.intersection(second_run_failures)
     792        new_failures = failures_with_patch - clean_tree_failures
     793        new_failures_string = ', '.join([failure_name.replace('TestWebKitAPI.', '') for failure_name in new_failures])
     794
     795        if new_failures:
     796            self._addToLog('stderr', '\nNew failures: {}\n'.format(new_failures))
     797            self.finished(FAILURE)
     798            self.build.results = FAILURE
     799            message = 'Found {} new API Tests failures: {}'.format(len(new_failures), new_failures_string)
     800            self.descriptionDone = message
     801            self.build.buildFinished([message], FAILURE)
     802        else:
     803            self._addToLog('stderr', '\nNo new failures\n')
     804            self.finished(SUCCESS)
     805            self.build.results = SUCCESS
     806            self.descriptionDone = 'Passed API tests'
     807            message = 'Found {} pre-existing API tests failures'.format(len(clean_tree_failures))
     808            self.build.buildFinished([message], SUCCESS)
     809
     810    @defer.inlineCallbacks
     811    def _addToLog(self, logName, message):
     812        try:
     813            log = self.getLog(logName)
     814        except KeyError:
     815            log = yield self.addLog(logName)
     816        log.addStdout(message)
     817
     818    def getBuildStepByName(self, name):
     819        for step in self.build.executedSteps:
     820            if step.name == name:
     821                return step
     822        return None
     823
     824    @defer.inlineCallbacks
     825    def getTestsResults(self, name):
     826        step = self.getBuildStepByName(name)
     827        if not step:
     828            self._addToLog('stderr', 'ERROR: step not found: {}'.format(step))
     829            defer.returnValue(None)
     830
     831        logs = yield self.master.db.logs.getLogs(step.stepid)
     832        log = next((log for log in logs if log['name'] == u'json'), None)
     833        if not log:
     834            self._addToLog('stderr', 'ERROR: log for step not found: {}'.format(step))
     835            defer.returnValue(None)
     836
     837        lastline = int(max(0, log['num_lines'] - 1))
     838        logLines = yield self.master.db.logs.getLogLines(log['id'], 0, lastline)
     839        if log['type'] == 's':
     840            logLines = ''.join([line[1:] for line in logLines.splitlines()])
     841
     842        try:
     843            self.results[name] = json.loads(logLines)
     844        except Exception as ex:
     845            self._addToLog('stderr', 'ERROR: unable to parse data, exception: {}'.format(ex))
     846
    713847
    714848class ArchiveTestResults(shell.ShellCommand):
  • trunk/Tools/BuildSlaveSupport/ews-build/steps_unittest.py

    r242969 r243342  
    3737from steps import *
    3838
     39# Workaround for https://github.com/buildbot/buildbot/issues/4669
     40from buildbot.test.fake.fakebuild import FakeBuild
     41FakeBuild.addStepsAfterCurrentStep = lambda FakeBuild, step_factories: None
     42
    3943
    4044class ExpectMasterShellCommand(object):
  • trunk/Tools/ChangeLog

    r243334 r243342  
     12019-03-21  Aakash Jain  <aakash_jain@apple.com>
     2
     3        [ews-build] Retry API test in case of failures
     4        https://bugs.webkit.org/show_bug.cgi?id=196004
     5
     6        Reviewed by Lucas Forschler.
     7
     8        * BuildSlaveSupport/ews-build/steps.py:
     9        (UnApplyPatchIfRequired.doStepIf): Updated doStepIf to include patchFailedAPITests.
     10        (CompileWebKitToT.doStepIf): Ditto.
     11        (RunAPITests.evaluateCommand): Check if tests failed and retry them if required.
     12        (ReRunAPITests): Re-run API tests.
     13        (ReRunAPITests.evaluateCommand): Check if tests failed and retry on clean build if required.
     14        (RunAPITestsWithoutPatch): Run API tests without patch.
     15        (RunAPITestsWithoutPatch.doStepIf):
     16        (RunAPITestsWithoutPatch.hideStepIf):
     17        (RunAPITestsWithoutPatch.evaluateCommand):
     18        (AnalyzeAPITestsResults): Analyze API test results from previous runs.
     19        (AnalyzeAPITestsResults.start):
     20        (AnalyzeAPITestsResults.analyzeResults): Analyze API test results.
     21        (AnalyzeAPITestsResults.getBuildStepByName): Search for a build step by name.
     22        (AnalyzeAPITestsResults.getTestsResults): Get the test results from previous API tesst steps.
     23        * BuildSlaveSupport/ews-build/steps_unittest.py: Monkey patched FakeBuild.
     24
    1252019-03-21  Aakash Jain  <aakash_jain@apple.com>
    226
Note: See TracChangeset for help on using the changeset viewer.