| Index: net/data/verify_certificate_chain_unittest/rebase-errors.py
|
| diff --git a/net/data/verify_certificate_chain_unittest/rebase-errors.py b/net/data/verify_certificate_chain_unittest/rebase-errors.py
|
| index 0ac03b6600ac7f581ceb0a2f3057e0486ef2f64c..dfc9d93751d7ac199a6a541c084a5340aee82ba4 100755
|
| --- a/net/data/verify_certificate_chain_unittest/rebase-errors.py
|
| +++ b/net/data/verify_certificate_chain_unittest/rebase-errors.py
|
| @@ -14,19 +14,47 @@ To use this run the affected tests, and then pass the input to this script
|
| $ ./out/Release/net_unittests --gtest_filter="*VerifyCertificateChain*" | \
|
| net/data/verify_certificate_chain_unittest/rebase-errors.py
|
|
|
| -The script will search the unit-test (results.txt in above example) and look
|
| -for failure lines and the corresponding actual error string.
|
| +The script works by scanning the stdout looking for gtest failures when
|
| +comparing "errors.ToDebugString()". The C++ test side should have been
|
| +instrumented to dump out the test file's path on mismatch.
|
|
|
| -It will then go and update the corresponding .pem and .py file.
|
| +This script will then update the corresponding file(s) -- a .pem file, and
|
| +possibly an accompanying .py file.
|
| """
|
|
|
| import common
|
| -import glob
|
| import os
|
| import sys
|
| import re
|
|
|
|
|
| +# Regular expression to find the failed errors in test stdout.
|
| +# * Group 1 of the match is the actual error text (backslash-escaped)
|
| +# * Group 2 of the match is file path (relative to //src) where the expected
|
| +# errors were read from.
|
| +failed_test_regex = re.compile(r"""
|
| +Value of: errors.ToDebugString\(\)
|
| + Actual: "(.*)"
|
| +(?:.|\n)+?
|
| +Test file: (.*)
|
| +""", re.MULTILINE)
|
| +
|
| +
|
| +# Regular expression to find the ERRORS block (and any text above it) in a PEM
|
| +# file. The assumption is that ERRORS is not the very first block in the file
|
| +# (since it looks for an -----END to precede it).
|
| +# * Group 1 of the match is the ERRORS block content and any comments
|
| +# immediately above it.
|
| +errors_block_regex = re.compile(r""".*
|
| +-----END .*?-----
|
| +
|
| +(.*?
|
| +-----BEGIN ERRORS-----
|
| +.*?
|
| +-----END ERRORS-----
|
| +)""", re.MULTILINE | re.DOTALL)
|
| +
|
| +
|
| def read_file_to_string(path):
|
| """Reads a file entirely to a string"""
|
| with open(path, 'r') as f:
|
| @@ -40,36 +68,17 @@ def write_string_to_file(data, path):
|
| f.write(data)
|
|
|
|
|
| -def get_file_paths_for_test(test_name):
|
| - """Returns the file paths (as a tuple) that define a particular unit test.
|
| - For instance given test name 'IntermediateLacksBasicConstraints' it would
|
| - return the paths to:
|
| -
|
| - * intermediate-lacks-basic-constraints.pem,
|
| - * generate-intermediate-lacks-basic-constraints.py
|
| - """
|
| - # The directory that this python script is stored in.
|
| - base_dir = os.path.dirname(os.path.realpath(__file__))
|
| +def get_py_path(pem_path):
|
| + """Returns the .py filepath used to generate the given .pem path, which may
|
| + or may not exist.
|
|
|
| - # The C++ test name is just a camel case verson of the file name. Rather than
|
| - # converting directly from camel case to a file name, it is simpler to just
|
| - # scan the file list and see which matches. (Not efficient but good enough).
|
| - paths = glob.glob(os.path.join(base_dir, '*.pem'))
|
| -
|
| - for pem_path in paths:
|
| - file_name = os.path.basename(pem_path)
|
| - file_name_no_extension = os.path.splitext(file_name)[0]
|
| -
|
| - # Strip the hyphens in file name to bring it closer to the camel case.
|
| - transformed = file_name_no_extension.replace('-', '')
|
| -
|
| - # Now all that differs is the case.
|
| - if transformed.lower() == test_name.lower():
|
| - py_file_name = 'generate-' + file_name_no_extension + '.py'
|
| - py_path = os.path.join(base_dir, py_file_name)
|
| - return (pem_path, py_path)
|
| -
|
| - return None
|
| + Some test files (notably those in verify_certificate_chain_unittest/ have a
|
| + "generate-XXX.py" script that builds the "XXX.pem" file. Build the path to
|
| + the corresponding "generate-XXX.py" (which may or may not exist)."""
|
| + file_name = os.path.basename(pem_path)
|
| + file_name_no_extension = os.path.splitext(file_name)[0]
|
| + py_file_name = 'generate-' + file_name_no_extension + '.py'
|
| + return os.path.join(os.path.dirname(pem_path), py_file_name)
|
|
|
|
|
| def replace_string(original, start, end, replacement):
|
| @@ -81,14 +90,14 @@ def fixup_pem_file(path, actual_errors):
|
| """Updates the ERRORS block in the test .pem file"""
|
| contents = read_file_to_string(path)
|
|
|
| - # This assumes that ERRORS is the last thing in file, and comes after the
|
| - # VERIFY_RESULT block.
|
| - kEndVerifyResult = '-----END VERIFY_RESULT-----'
|
| - contents = contents[0:contents.index(kEndVerifyResult)]
|
| - contents += kEndVerifyResult
|
| - contents += '\n'
|
| - contents += '\n'
|
| - contents += common.text_data_to_pem('ERRORS', actual_errors)
|
| + m = errors_block_regex.search(contents)
|
| +
|
| + if not m:
|
| + print "Couldn't find ERRORS block in %s" % (path)
|
| + return
|
| +
|
| + contents = replace_string(contents, m.start(1), m.end(1),
|
| + common.text_data_to_pem('ERRORS', actual_errors))
|
|
|
| # Update the file.
|
| write_string_to_file(contents, path)
|
| @@ -99,7 +108,7 @@ def fixup_py_file(path, actual_errors):
|
| contents = read_file_to_string(path)
|
|
|
| # This assumes that the errors variable uses triple quotes.
|
| - prog = re.compile(r'^errors = """(.*)"""', re.MULTILINE | re.DOTALL)
|
| + prog = re.compile(r'^errors = """(.*?)"""', re.MULTILINE | re.DOTALL)
|
| result = prog.search(contents)
|
|
|
| # Replace the stuff in between the triple quotes with the actual errors.
|
| @@ -110,21 +119,39 @@ def fixup_py_file(path, actual_errors):
|
| write_string_to_file(contents, path)
|
|
|
|
|
| -def fixup_test(test_name, actual_errors):
|
| - """Updates the test files used by |test_name|, setting the expected error to
|
| - |actual_errors|"""
|
| +def get_src_root():
|
| + """Returns the path to the enclosing //src directory. This assumes the
|
| + current script is inside the source tree."""
|
| + cur_dir = os.path.dirname(os.path.realpath(__file__))
|
|
|
| - # Determine the paths for the corresponding *.pem file and generate-*.py
|
| - pem_path, py_path = get_file_paths_for_test(test_name)
|
| + while True:
|
| + parent_dir, dirname = os.path.split(cur_dir)
|
| + # Check if it looks like the src/ root.
|
| + if dirname == "src" and os.path.isdir(os.path.join(cur_dir, "net")):
|
| + return cur_dir
|
| + if not parent_dir or parent_dir == cur_dir:
|
| + break
|
| + cur_dir = parent_dir
|
|
|
| - fixup_pem_file(pem_path, actual_errors)
|
| - fixup_py_file(py_path, actual_errors)
|
| + print "Couldn't find src dir"
|
| + sys.exit(1)
|
| +
|
| +
|
| +def get_abs_path(rel_path):
|
| + """Converts |rel_path| (relative to src) to a full path"""
|
| + return os.path.join(get_src_root(), rel_path)
|
| +
|
| +
|
| +def fixup_errors_for_file(actual_errors, pem_path):
|
| + """Updates the errors in |test_file_path| (.pem file) to match
|
| + |actual_errors|"""
|
|
|
| + fixup_pem_file(pem_path, actual_errors)
|
|
|
| -kTestNamePattern = (r'^\[ RUN \] VerifyCertificateChain/'
|
| - 'VerifyCertificateChainSingleRootTest/0\.(.*)$')
|
| -kValueOfLine = 'Value of: errors.ToDebugString()'
|
| -kActualPattern = '^ Actual: "(.*)"$'
|
| + # If the test has a generator script update it too.
|
| + py_path = get_py_path(pem_path)
|
| + if os.path.isfile(py_path):
|
| + fixup_py_file(py_path, actual_errors)
|
|
|
|
|
| def main():
|
| @@ -140,28 +167,11 @@ def main():
|
| print 'Reading input from stdin...'
|
| test_stdout = sys.stdin.read()
|
|
|
| - lines = test_stdout.split('\n')
|
| -
|
| - # Iterate over each line of the unit test stdout.
|
| - for i in range(len(lines) - 3):
|
| - # Figure out the name of the test.
|
| - m = re.search(kTestNamePattern, lines[i])
|
| - if not m:
|
| - continue
|
| - test_name = m.group(1)
|
| -
|
| - # Confirm that it is a failure having to do with the errors.
|
| - if lines[i + 2] != kValueOfLine:
|
| - continue
|
| -
|
| - # Get the actual error text (which in gtest output is escaped).
|
| - m = re.search(kActualPattern, lines[i + 3])
|
| - if not m:
|
| - continue
|
| - actual = m.group(1)
|
| - actual = actual.decode('string-escape')
|
| -
|
| - fixup_test(test_name, actual)
|
| + for m in failed_test_regex.finditer(test_stdout):
|
| + actual_errors = m.group(1)
|
| + actual_errors = actual_errors.decode('string-escape')
|
| + relative_test_path = m.group(2)
|
| + fixup_errors_for_file(actual_errors, get_abs_path(relative_test_path))
|
|
|
|
|
| if __name__ == "__main__":
|
|
|