Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: net/data/verify_certificate_chain_unittest/rebase-errors.py

Issue 2805213004: Refactor how net/data/verify_certificate_chain_unittest/* (Closed)
Patch Set: fix android Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2016 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Helper script to update the test error expectations based on actual results. 6 """Helper script to update the test error expectations based on actual results.
7 7
8 This is useful for regenerating test expectations after making changes to the 8 This is useful for regenerating test expectations after making changes to the
9 error format. 9 error format.
10 10
11 To use this run the affected tests, and then pass the input to this script 11 To use this run the affected tests, and then pass the input to this script
12 (either via stdin, or as the first argument). For instance: 12 (either via stdin, or as the first argument). For instance:
13 13
14 $ ./out/Release/net_unittests --gtest_filter="*VerifyCertificateChain*" | \ 14 $ ./out/Release/net_unittests --gtest_filter="*VerifyCertificateChain*" | \
15 net/data/verify_certificate_chain_unittest/rebase-errors.py 15 net/data/verify_certificate_chain_unittest/rebase-errors.py
16 16
17 The script works by scanning the stdout looking for gtest failures when 17 The script works by scanning the stdout looking for gtest failures when
18 comparing "errors.ToDebugString(chain)". The C++ test side should have been 18 comparing "errors.ToDebugString(chain)". The C++ test side should have been
19 instrumented to dump out the test file's path on mismatch. 19 instrumented to dump out the test file's path on mismatch.
20 20
21 This script will then update the corresponding file(s) -- a .pem file, and 21 This script will then update the corresponding .test file that contains the
22 possibly an accompanying .py file. 22 error expectation.
23 """ 23 """
24 24
25 import common
26 import os 25 import os
27 import sys 26 import sys
28 import re 27 import re
29 28
30
31 # Regular expression to find the failed errors in test stdout. 29 # Regular expression to find the failed errors in test stdout.
32 # * Group 1 of the match is the actual error text (backslash-escaped) 30 # * Group 1 of the match is the actual error text (backslash-escaped)
33 # * Group 2 of the match is file path (relative to //src) where the expected 31 # * Group 2 of the match is file path (relative to //src) where the expected
34 # errors were read from. 32 # errors were read from.
35 failed_test_regex = re.compile(r""" 33 failed_test_regex = re.compile(r"""
36 Value of: errors.ToDebugString\((?:test.chain)?\) 34 Value of: errors.ToDebugString\((?:test.chain)?\)
37 Actual: "(.*)" 35 Actual: "(.*)"
38 (?:.|\n)+? 36 (?:.|\n)+?
39 Test file: (.*) 37 Test file: (.*[.]test)
40 """, re.MULTILINE) 38 """, re.MULTILINE)
41 39
42 40
43 # Regular expression to find the ERRORS block (and any text above it) in a PEM
44 # file. The assumption is that ERRORS is not the very first block in the file
45 # (since it looks for an -----END to precede it).
46 # * Group 1 of the match is the ERRORS block content and any comments
47 # immediately above it.
48 errors_block_regex = re.compile(r""".*
49 -----END .*?-----
50
51 (.*?
52 -----BEGIN ERRORS-----
53 .*?
54 -----END ERRORS-----
55 )""", re.MULTILINE | re.DOTALL)
56
57
58 def read_file_to_string(path): 41 def read_file_to_string(path):
59 """Reads a file entirely to a string""" 42 """Reads a file entirely to a string"""
60 with open(path, 'r') as f: 43 with open(path, 'r') as f:
61 return f.read() 44 return f.read()
62 45
63 46
64 def write_string_to_file(data, path): 47 def write_string_to_file(data, path):
65 """Writes a string to a file""" 48 """Writes a string to a file"""
66 print "Writing file %s ..." % (path) 49 print "Writing file %s ..." % (path)
67 with open(path, "w") as f: 50 with open(path, "w") as f:
68 f.write(data) 51 f.write(data)
69 52
70 53
71 def get_py_path(pem_path):
72 """Returns the .py filepath used to generate the given .pem path, which may
73 or may not exist.
74
75 Some test files (notably those in verify_certificate_chain_unittest/ have a
76 "generate-XXX.py" script that builds the "XXX.pem" file. Build the path to
77 the corresponding "generate-XXX.py" (which may or may not exist)."""
78 file_name = os.path.basename(pem_path)
79 file_name_no_extension = os.path.splitext(file_name)[0]
80 py_file_name = 'generate-' + file_name_no_extension + '.py'
81 return os.path.join(os.path.dirname(pem_path), py_file_name)
82
83
84 def replace_string(original, start, end, replacement):
85 """Replaces the specified range of |original| with |replacement|"""
86 return original[0:start] + replacement + original[end:]
87
88
89 def fixup_pem_file(path, actual_errors):
90 """Updates the ERRORS block in the test .pem file"""
91 contents = read_file_to_string(path)
92
93 m = errors_block_regex.search(contents)
94
95 if not m:
96 contents += '\n' + common.text_data_to_pem('ERRORS', actual_errors)
97 else:
98 contents = replace_string(contents, m.start(1), m.end(1),
99 common.text_data_to_pem('ERRORS', actual_errors))
100
101 # Update the file.
102 write_string_to_file(contents, path)
103
104
105 def fixup_py_file(path, actual_errors):
106 """Replaces the 'errors = XXX' section of the test's python script"""
107 contents = read_file_to_string(path)
108
109 # This assumes that the errors variable uses triple quotes.
110 prog = re.compile(r'^errors = (""".*?"""|None)', re.MULTILINE | re.DOTALL)
111 result = prog.search(contents)
112
113 # Replace the stuff in between the triple quotes with the actual errors.
114 contents = replace_string(contents, result.start(1), result.end(1),
115 '"""' + actual_errors + '"""')
116
117 # Update the file.
118 write_string_to_file(contents, path)
119
120
121 def get_src_root(): 54 def get_src_root():
122 """Returns the path to the enclosing //src directory. This assumes the 55 """Returns the path to the enclosing //src directory. This assumes the
123 current script is inside the source tree.""" 56 current script is inside the source tree."""
124 cur_dir = os.path.dirname(os.path.realpath(__file__)) 57 cur_dir = os.path.dirname(os.path.realpath(__file__))
125 58
126 while True: 59 while True:
127 parent_dir, dirname = os.path.split(cur_dir) 60 parent_dir, dirname = os.path.split(cur_dir)
128 # Check if it looks like the src/ root. 61 # Check if it looks like the src/ root.
129 if dirname == "src" and os.path.isdir(os.path.join(cur_dir, "net")): 62 if dirname == "src" and os.path.isdir(os.path.join(cur_dir, "net")):
130 return cur_dir 63 return cur_dir
131 if not parent_dir or parent_dir == cur_dir: 64 if not parent_dir or parent_dir == cur_dir:
132 break 65 break
133 cur_dir = parent_dir 66 cur_dir = parent_dir
134 67
135 print "Couldn't find src dir" 68 print "Couldn't find src dir"
136 sys.exit(1) 69 sys.exit(1)
137 70
138 71
139 def get_abs_path(rel_path): 72 def get_abs_path(rel_path):
140 """Converts |rel_path| (relative to src) to a full path""" 73 """Converts |rel_path| (relative to src) to a full path"""
141 return os.path.join(get_src_root(), rel_path) 74 return os.path.join(get_src_root(), rel_path)
142 75
143 76
144 def fixup_errors_for_file(actual_errors, pem_path): 77 def fixup_errors_for_file(actual_errors, test_file_path):
145 """Updates the errors in |test_file_path| (.pem file) to match 78 """Updates the errors in |test_file_path| to match |actual_errors|"""
146 |actual_errors|""" 79 contents = read_file_to_string(test_file_path)
147 80
148 fixup_pem_file(pem_path, actual_errors) 81 header = "\nexpected_errors:\n"
82 index = contents.find(header)
83 if index < 0:
84 print "Couldn't find expected_errors"
85 sys.exit(1)
149 86
150 # If the test has a generator script update it too. 87 # The rest of the file contains the errors (overwrite).
151 py_path = get_py_path(pem_path) 88 contents = contents[0:index] + header + actual_errors
152 if os.path.isfile(py_path): 89
153 fixup_py_file(py_path, actual_errors) 90 write_string_to_file(contents, test_file_path)
154 91
155 92
156 def main(): 93 def main():
157 if len(sys.argv) > 2: 94 if len(sys.argv) > 2:
158 print 'Usage: %s [path-to-unittest-stdout]' % (sys.argv[0]) 95 print 'Usage: %s [path-to-unittest-stdout]' % (sys.argv[0])
159 sys.exit(1) 96 sys.exit(1)
160 97
161 # Read the input either from a file, or from stdin. 98 # Read the input either from a file, or from stdin.
162 test_stdout = None 99 test_stdout = None
163 if len(sys.argv) == 2: 100 if len(sys.argv) == 2:
164 test_stdout = read_file_to_string(sys.argv[1]) 101 test_stdout = read_file_to_string(sys.argv[1])
165 else: 102 else:
166 print 'Reading input from stdin...' 103 print 'Reading input from stdin...'
167 test_stdout = sys.stdin.read() 104 test_stdout = sys.stdin.read()
168 105
169 for m in failed_test_regex.finditer(test_stdout): 106 for m in failed_test_regex.finditer(test_stdout):
170 actual_errors = m.group(1) 107 actual_errors = m.group(1)
171 actual_errors = actual_errors.decode('string-escape') 108 actual_errors = actual_errors.decode('string-escape')
172 relative_test_path = m.group(2) 109 relative_test_path = m.group(2)
173 fixup_errors_for_file(actual_errors, get_abs_path(relative_test_path)) 110 fixup_errors_for_file(actual_errors, get_abs_path(relative_test_path))
174 111
175 112
176 if __name__ == "__main__": 113 if __name__ == "__main__":
177 main() 114 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698