Files
palemoon27/testing/mochitest/bisection.py
T
roytam1 9489c945bf import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1169798 - Refresh the marionette server's window reference when switching between windows to avoid intermittent exception.;r=ato (606c3f22d8)
- Bug 1169600 - Avoid misleading exception in message listeners in marionette server. r=ato (ec8d12becf)
- Bug 1174941: Update server capabilities that are set on startup; r=ato (9ca7a8be79)
- Bug 1174941: Remove all capabilities from desired capabilities if they are in the session capabilitiesand in requiredCapabilities; r=ato (453c905a90)
- Bug 1174941: Update conditional to switch statement to allow more processing of capabilities; r=ato (1460802be1)
- NO BUG: correct import in marionette about_pages tests r=me DONTBUILD (cad6eecb22)
- Bug 1169600 - Remove message listeners intended to coordinate registering a new browser with marionette once the browser has been registered. r=ato (86fed67200)
- Bug 1165449: Add the ability to set a proxy via capabilities on Marionette session start; r=jgriffin (b2107767bb)
- Bug 1178468 - Update marionette cookie support to use nsICookie2. r=jgriffin (90a140c915)
- Bug 1196920: Add specificationLevel capability to Marionette; r=jgriffin (d64f1b7b2e)
- Bug 1197131: Use dispatcher for listener getCurrentUrl (b2ca32f3d0)
- Bug 1197146: Part 2: Use dispatcher for listener findElementsContent (f324b851a6)
- Bug 1197146: Part 1: Prime dispatcher in listener to resolve promises (947dc5bd29)
- Bug 1197133: Use dispatcher for listener getTitle (76b884bb21)
- Bug 1197141: Use dispatcher for listener getPageSource (7ad171b976)
- Bug 1197143: Use dispatcher for listener goBack (c8302aa896)
- Bug 1191432 - improving coverage for marionette accessibility checks. r=automatedtester (4ce11c5110)
- Bug 1197146: Part 3: Use dispatcher for listener findElementContent (26fe7c4198)
- Bug 1197146: Part 4: Use dispatcher for listener isElementSelected (de51ad7e17)
- Bug 1197146: Part 5: Use dispatcher for listener getElementLocation (5c0620ad1d)
- Bug 1197146: Part 6: Use dispatcher for listener clearElement (811670ed39)
- Bug 1155716: Part 1: Remove submitElement from Marionette (52122d817e)
- Bug 1197146: Part 7: Use dispatcher for listener isElementDisplayed (e7408e94ce)
- Bug 1197146: Part 8: Use dispatcher for listener getElementValueOfCssProperty (591c71ba82)
- Bug 1196987: Update UUID returned to be a valid UUID 4; r=jgriffin (e0b19efc78)
- Bug 1152682: Correct invalid selector errors in elements.js (5466b28ff7)
- Bug 1194224 - adding support for Shadow DOM in marionette. r=automatedtester (0f2b2580b9)
- Bug 1200420 - Better handling of startup_timeout, r=AutomatedTester (0ae69578ab)
- Bug 1139158 - Actions made availabe via marionette_driver object. r=jgriffin (4713e8fc1e)
- goanna -> gecko (fa2a0d674f)
- Bug 1143565: Change requirements to not be fixed to a specific marionette transport and driver; r=chmanchester (cbc9e7eab6)
- Bug 1150050 - Bump manifestparser to v1.1 and marionette-client to v0.9.3 to pick up tagging feature, r=AutomatedTester (f63a01da3b)
- Bug 1157823 - Update dependency to reflect that the marionette client requires a more recent mozhttpd. r=ato (594cde8a5e)
- Bug 1155260: Fix base URL override in Marionette runner (a99bd14cac)
- Bug 1159816 - Bump marionette_client to 0.12. DONTBUILD. CLOSED TREE. r=chmanchester (779b4c9866)
- Bug 1161209 - Bump marionette-driver to 0.7, marionette-client to 0.13, r=AutomatedTester (175cc7adea)
- Bug 1163833 - Add integration with browsermob-proxy, r=dburns (bd90184ee1)
- Bug 983821 - 'marionette' cli entrypoint doesn't have access to proper packages. r=dburns (17d4abf193)
- Bug 1168997 - Bump marionette-client to 0.14, r=dburns (5c10bd3404)
- Bug 1169751 - Bump marionette-driver to 0.8, marionette-client to 0.15, r=dburns (95b3c45faa)
- Bug 1177513 - Bump marionette-client to 0.16, r=dburns (d1228ed4bb)
- Bug 902125 - Add a version config/flag for Python Marionette. r=dburns (f72e7463d7)
- Bug 1177780 - remove useless stuff in automation.py. r=jgriffin (d0d0baf473)
- partial of  Bug 1170332 - Fix |mach robocop SINGLE_TEST|. (0838005e10)
- goanna->gecko (ef97631963)
- Bug 1162285 - Remove unused environment vars on Android; r=jmaher (bf6b44a3ae)
- Bug 1160324 - Handle missing robocopApk files in runtestsremote.py. r=gbrown (3d5c874630)
- Bug 1169476 -- Implement |mach robocop --serve|. r=gbrown (11039daa39)
- Bug 1160351 - Improve newline handling in getLogcat; r=bc Bug 1160351 - Bustage fix for 57c6c589cfa1 on a CLOSED TREE (d64b410ef4)
- Bug 1137289 - Guard against dumpsys failure in DroidADB; r=jmaher (4a39532464)
- Bug 1175540 - Reduce timeouts for many adb devicemanager calls; r=mcote (528209a4d6)
- bit of Bug 1160662 - Refer to robocop.ini in $OBJDIR/_tests, not $OBJDIR (c288d73c16)
- Bug 1162479 - Fix mochitest make target regression with duplicate extraProfilePath, r=chmanchester (53251cff28)
- Bug 1151533 - Upgrade manually set tc xre r=me (3bb5f8fecd)
- Bug 1161709 - Pull from artifacts for xulrunner instead of s3 directly r=me (6314094083)
- Bug 1144528 - Use hg share on testers r=garndt ON CLOSED TREE (46779ab50c)
- Bug 1142565 - Update tester images to include same fonts as test slaves r=garndt (cf9e546dfa)
- bits of Bug 1144927 - Directly bake in linux64-minidump_stackwak to tester images r=garndt (8b1f3ff968)
- Bug 1157308 - part 1 - Reduce the leak threshold for content processes more. r=erahm (177289cf32)
- Bug 1157308 - part 2 - Reduce the content process leak limit on OS X. r=erahm (98d14f78cd)
- Bug 1173114 - Fallback to chunk-by-dir if runtimes file not found, r=ahal (c7cb797636)
- Bug 1026290 - Avoid TypeError during Android mochitest-chrome; r=chmanchester (a8112e6ca1)
- Bug 1173971 - Force core Xlib events on GTK3. r=karlt (17fc2475e0)
- Bug 1144194 - Only parse test manifests once in mochitest, r=jmaher (37f5c3a764)
- Bug 1171971 - Move test_paths argument out of mach and into mochitest; remove --test-path, r=chmanchester (3ab9acf758)
- Bug 1178154 - move ShutdownLeaks and LSANLeaks from automationutils to mochitest. r=jgriffin (e8ec293a91)
- Bug 1156982 - Add separators to BloatView output. r=froydnj (ac92a67ba9)
- Bug 1152872 - Don't attempt to leak-check the tools that we run as part of the setup for the mochitest suite; r=mccr8 (dd78bcc8bc)
- Bug 1158227 - part 1 - don't run TSan on test tools or the xpcshell HTTP server in mochitests; r=jmaher (59bbf448e5)
- Bug 1158227 - part 2 - set TSAN_OPTIONS environment variable in automationutils.py for TSan; r=jmaher (66e607b25e)
- Bug 1091284 - Remove systemMemory, environment from automationutils. r=jgriffin (817860ab08)
2022-03-31 09:48:09 +08:00

271 lines
11 KiB
Python

import math
import mozinfo
class Bisect(object):
"Class for creating, bisecting and summarizing for --bisect-chunk option."
def __init__(self, harness):
super(Bisect, self).__init__()
self.summary = []
self.contents = {}
self.repeat = 10
self.failcount = 0
self.max_failures = 3
def setup(self, tests):
"This method is used to initialize various variables that are required for test bisection"
status = 0
self.contents.clear()
# We need totalTests key in contents for sanity check
self.contents['totalTests'] = tests
self.contents['tests'] = tests
self.contents['loop'] = 0
return status
def reset(self, expectedError, result):
"This method is used to initialize self.expectedError and self.result for each loop in runtests."
self.expectedError = expectedError
self.result = result
def get_tests_for_bisection(self, options, tests):
"Make a list of tests for bisection from a given list of tests"
bisectlist = []
for test in tests:
bisectlist.append(test)
if test.endswith(options.bisectChunk):
break
return bisectlist
def pre_test(self, options, tests, status):
"This method is used to call other methods for setting up variables and getting the list of tests for bisection."
if options.bisectChunk == "default":
return tests
# The second condition in 'if' is required to verify that the failing
# test is the last one.
elif 'loop' not in self.contents or not self.contents['tests'][-1].endswith(options.bisectChunk):
tests = self.get_tests_for_bisection(options, tests)
status = self.setup(tests)
return self.next_chunk_binary(options, status)
def post_test(self, options, expectedError, result):
"This method is used to call other methods to summarize results and check whether a sanity check is done or not."
self.reset(expectedError, result)
status = self.summarize_chunk(options)
# Check whether sanity check has to be done. Also it is necessary to check whether options.bisectChunk is present
# in self.expectedError as we do not want to run if it is "default".
if status == -1 and options.bisectChunk in self.expectedError:
# In case we have a debug build, we don't want to run a sanity
# check, will take too much time.
if mozinfo.info['debug']:
return status
testBleedThrough = self.contents['testsToRun'][0]
tests = self.contents['totalTests']
tests.remove(testBleedThrough)
# To make sure that the failing test is dependent on some other
# test.
if options.bisectChunk in testBleedThrough:
return status
status = self.setup(tests)
self.summary.append("Sanity Check:")
return status
def next_chunk_reverse(self, options, status):
"This method is used to bisect the tests in a reverse search fashion."
# Base Cases.
if self.contents['loop'] <= 1:
self.contents['testsToRun'] = self.contents['tests']
if self.contents['loop'] == 1:
self.contents['testsToRun'] = [self.contents['tests'][-1]]
self.contents['loop'] += 1
return self.contents['testsToRun']
if 'result' in self.contents:
if self.contents['result'] == "PASS":
chunkSize = self.contents['end'] - self.contents['start']
self.contents['end'] = self.contents['start'] - 1
self.contents['start'] = self.contents['end'] - chunkSize
# self.contents['result'] will be expected error only if it fails.
elif self.contents['result'] == "FAIL":
self.contents['tests'] = self.contents['testsToRun']
status = 1 # for initializing
# initialize
if status:
totalTests = len(self.contents['tests'])
chunkSize = int(math.ceil(totalTests / 10.0))
self.contents['start'] = totalTests - chunkSize - 1
self.contents['end'] = totalTests - 2
start = self.contents['start']
end = self.contents['end'] + 1
self.contents['testsToRun'] = self.contents['tests'][start:end]
self.contents['testsToRun'].append(self.contents['tests'][-1])
self.contents['loop'] += 1
return self.contents['testsToRun']
def next_chunk_binary(self, options, status):
"This method is used to bisect the tests in a binary search fashion."
# Base cases.
if self.contents['loop'] <= 1:
self.contents['testsToRun'] = self.contents['tests']
if self.contents['loop'] == 1:
self.contents['testsToRun'] = [self.contents['tests'][-1]]
self.contents['loop'] += 1
return self.contents['testsToRun']
# Initialize the contents dict.
if status:
totalTests = len(self.contents['tests'])
self.contents['start'] = 0
self.contents['end'] = totalTests - 2
mid = (self.contents['start'] + self.contents['end']) / 2
if 'result' in self.contents:
if self.contents['result'] == "PASS":
self.contents['end'] = mid
elif self.contents['result'] == "FAIL":
self.contents['start'] = mid + 1
mid = (self.contents['start'] + self.contents['end']) / 2
start = mid + 1
end = self.contents['end'] + 1
self.contents['testsToRun'] = self.contents['tests'][start:end]
if not self.contents['testsToRun']:
self.contents['testsToRun'].append(self.contents['tests'][mid])
self.contents['testsToRun'].append(self.contents['tests'][-1])
self.contents['loop'] += 1
return self.contents['testsToRun']
def summarize_chunk(self, options):
"This method is used summarize the results after the list of tests is run."
if options.bisectChunk == "default":
# if no expectedError that means all the tests have successfully
# passed.
if len(self.expectedError) == 0:
return -1
options.bisectChunk = self.expectedError.keys()[0]
self.summary.append(
"\tFound Error in test: %s" %
options.bisectChunk)
return 0
# If options.bisectChunk is not in self.result then we need to move to
# the next run.
if options.bisectChunk not in self.result:
return -1
self.summary.append("\tPass %d:" % self.contents['loop'])
if len(self.contents['testsToRun']) > 1:
self.summary.append(
"\t\t%d test files(start,end,failing). [%s, %s, %s]" % (len(
self.contents['testsToRun']),
self.contents['testsToRun'][0],
self.contents['testsToRun'][
-2],
self.contents['testsToRun'][
-1]))
else:
self.summary.append(
"\t\t1 test file [%s]" %
self.contents['testsToRun'][0])
return self.check_for_intermittent(options)
if self.result[options.bisectChunk] == "PASS":
self.summary.append("\t\tno failures found.")
if self.contents['loop'] == 1:
status = -1
else:
self.contents['result'] = "PASS"
status = 0
elif self.result[options.bisectChunk] == "FAIL":
if 'expectedError' not in self.contents:
self.summary.append("\t\t%s failed." %
self.contents['testsToRun'][-1])
self.contents['expectedError'] = self.expectedError[
options.bisectChunk]
status = 0
elif self.expectedError[options.bisectChunk] == self.contents['expectedError']:
self.summary.append(
"\t\t%s failed with expected error." % self.contents['testsToRun'][-1])
self.contents['result'] = "FAIL"
status = 0
# This code checks for test-bleedthrough. Should work for any
# algorithm.
numberOfTests = len(self.contents['testsToRun'])
if numberOfTests < 3:
# This means that only 2 tests are run. Since the last test
# is the failing test itself therefore the bleedthrough
# test is the first test
self.summary.append(
"TEST-UNEXPECTED-FAIL | %s | Bleedthrough detected, this test is the root cause for many of the above failures" %
self.contents['testsToRun'][0])
status = -1
else:
self.summary.append(
"\t\t%s failed with different error." % self.contents['testsToRun'][-1])
status = -1
return status
def check_for_intermittent(self, options):
"This method is used to check whether a test is an intermittent."
if self.result[options.bisectChunk] == "PASS":
self.summary.append(
"\t\tThe test %s passed." %
self.contents['testsToRun'][0])
if self.repeat > 0:
# loop is set to 1 to again run the single test.
self.contents['loop'] = 1
self.repeat -= 1
return 0
else:
if self.failcount > 0:
# -1 is being returned as the test is intermittent, so no need to bisect further.
return -1
# If the test does not fail even once, then proceed to next chunk for bisection.
# loop is set to 2 to proceed on bisection.
self.contents['loop'] = 2
return 1
elif self.result[options.bisectChunk] == "FAIL":
self.summary.append(
"\t\tThe test %s failed." %
self.contents['testsToRun'][0])
self.failcount += 1
self.contents['loop'] = 1
self.repeat -= 1
# self.max_failures is the maximum number of times a test is allowed
# to fail to be called an intermittent. If a test fails more than
# limit set, it is a perma-fail.
if self.failcount < self.max_failures:
if self.repeat == 0:
# -1 is being returned as the test is intermittent, so no need to bisect further.
return -1
return 0
else:
self.summary.append(
"TEST-UNEXPECTED-FAIL | %s | Bleedthrough detected, this test is the root cause for many of the above failures" %
self.contents['testsToRun'][0])
return -1
def print_summary(self):
"This method is used to print the recorded summary."
print "Bisection summary:"
for line in self.summary:
print line