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

Side by Side Diff: scripts/slave/unittests/recipe_configs_test.py

Issue 17635005: Make blink_trybot recipe work on windows (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Fix presubmit + move polyfill (retry) Created 7 years, 5 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 | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 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 """Provides test coverage for common recipe configurations. 6 """Provides test coverage for common recipe configurations.
7 7
8 recipe config expectations are located in ../recipe_configs_test/*.expected 8 recipe config expectations are located in ../recipe_configs_test/*.expected
9 9
10 In training mode, this will loop over every config item in ../recipe_configs.py 10 In training mode, this will loop over every config item in ../recipe_configs.py
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 return file_name, None, None 81 return file_name, None, None
82 82
83 for config_name, fn in ctx.CONFIG_ITEMS.iteritems(): 83 for config_name, fn in ctx.CONFIG_ITEMS.iteritems():
84 if fn.NO_TEST or fn.IS_ROOT: 84 if fn.NO_TEST or fn.IS_ROOT:
85 continue 85 continue
86 try: 86 try:
87 result = covered(fn, make_item()) 87 result = covered(fn, make_item())
88 if result.complete(): 88 if result.complete():
89 ret[config_name] = result.as_jsonish() 89 ret[config_name] = result.as_jsonish()
90 except recipe_configs_util.BadConf, e: 90 except recipe_configs_util.BadConf, e:
91 ret[config_name] = e.message 91 ret[config_name] = str(e)
92 return file_name, (ctx.TEST_NAME_FORMAT % var_assignments), ret 92 return file_name, (ctx.TEST_NAME_FORMAT % var_assignments), ret
93 except Exception, e: 93 except Exception, e:
94 print 'Caught exception [%s] with args %s: %s' % (e, args, config_name) 94 print 'Caught exception [%s] with args %s: %s' % (e, args, config_name)
95 95
96 96
97 def train_from_tests(args): 97 def train_from_tests(args):
98 file_name, _, configuration_results = evaluate_configurations(args) 98 file_name, _, configuration_results = evaluate_configurations(args)
99 if configuration_results is not None: 99 if configuration_results is not None:
100 if configuration_results: 100 if configuration_results:
101 print 'Writing', file_name 101 print 'Writing', file_name
102 with open(file_name, 'w') as f: 102 with open(file_name, 'wb') as f:
103 json.dump(configuration_results, f, sort_keys=True, indent=2) 103 json.dump(configuration_results, f, sort_keys=True, indent=2)
104 else: 104 else:
105 print 'Empty', file_name 105 print 'Empty', file_name
106 106
107 if not configuration_results: # None or {} 107 if not configuration_results: # None or {}
108 if os.path.exists(file_name): 108 if os.path.exists(file_name):
109 os.unlink(file_name) 109 os.unlink(file_name)
110 return True 110 return True
111 111
112 112
113 def load_tests(loader, _standard_tests, _pattern): 113 def load_tests(loader, _standard_tests, _pattern):
114 """This method is invoked by unittest.main's automatic testloader.""" 114 """This method is invoked by unittest.main's automatic testloader."""
115 def create_test_class(args): 115 def create_test_class(args):
116 file_name, test_name_suffix, configuration_results = args 116 file_name, test_name_suffix, configuration_results = args
117 if configuration_results is None: 117 if configuration_results is None:
118 return 118 return
119 119
120 json_expectation = {} 120 json_expectation = {}
121 if os.path.exists(file_name): 121 if os.path.exists(file_name):
122 with open(file_name, 'r') as f: 122 with open(file_name, 'rb') as f:
123 json_expectation = json.load(f) 123 json_expectation = json.load(f)
124 124
125 class RecipeConfigsTest(unittest.TestCase): 125 class RecipeConfigsTest(unittest.TestCase):
126 def testNoLeftovers(self): 126 def testNoLeftovers(self):
127 """add_test_methods() should completely drain json_expectation.""" 127 """add_test_methods() should completely drain json_expectation."""
128 self.assertEqual(json_expectation, {}) 128 self.assertEqual(json_expectation, {})
129 129
130 @classmethod 130 @classmethod
131 def add_test_methods(cls): 131 def add_test_methods(cls):
132 for name, result in configuration_results.iteritems(): 132 for name, result in configuration_results.iteritems():
(...skipping 13 matching lines...) Expand all
146 146
147 suite = unittest.TestSuite() 147 suite = unittest.TestSuite()
148 for test_class in map(create_test_class, data): 148 for test_class in map(create_test_class, data):
149 if test_class is None: 149 if test_class is None:
150 continue 150 continue
151 suite.addTest(loader.loadTestsFromTestCase(test_class)) 151 suite.addTest(loader.loadTestsFromTestCase(test_class))
152 return suite 152 return suite
153 153
154 154
155 def multiprocessing_init(): 155 def multiprocessing_init():
156 # HACK: multiprocessing doesn't work with atexit, so shim os._exit instead. 156 init_recipe_modules()
157 # This allows us to save exactly one coverage file per subprocess 157
158 # HACK: multiprocessing doesn't work with atexit, so shim the exit functions
159 # instead. This allows us to save exactly one coverage file per subprocess.
158 # pylint: disable=W0212 160 # pylint: disable=W0212
159 init_recipe_modules() 161 real_os_exit = multiprocessing.forking.exit
160 real_os_exit = os._exit
161 def exitfn(code): 162 def exitfn(code):
162 COVERAGE.save() 163 COVERAGE.save()
163 real_os_exit(code) 164 real_os_exit(code)
164 os._exit = exitfn 165 multiprocessing.forking.exit = exitfn
166
167 # This check mirrors the logic in multiprocessing.forking.exit
168 if sys.platform != 'win32':
169 # Even though multiprocessing.forking.exit is defined, it's not used in the
170 # non-win32 version multiprocessing.forking.Popen... *loss for words*
171 os._exit = exitfn
165 172
166 173
167 def coverage_parallel_map(fn): 174 def coverage_parallel_map(fn):
168 combination_generator = ( 175 combination_generator = (
169 (mod_id, var_assignments) 176 (mod_id, var_assignments)
170 for mod_id, mod in RECIPE_MODULES.__dict__.iteritems() 177 for mod_id, mod in RECIPE_MODULES.__dict__.iteritems()
171 if mod_id[0] != '_' and mod.CONFIG_CTX 178 if mod_id[0] != '_' and mod.CONFIG_CTX
172 for var_assignments in imap(dict, product(*[ 179 for var_assignments in imap(dict, product(*[
173 [(key_name, val) for val in vals] 180 [(key_name, val) for val in vals]
174 for key_name, vals in mod.CONFIG_CTX.VAR_TEST_MAP.iteritems() 181 for key_name, vals in mod.CONFIG_CTX.VAR_TEST_MAP.iteritems()
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 total_covered = COVERAGE.report() 230 total_covered = COVERAGE.report()
224 if total_covered != 100.0: 231 if total_covered != 100.0:
225 print 'FATAL: Recipes configs are not at 100% coverage.' 232 print 'FATAL: Recipes configs are not at 100% coverage.'
226 retcode = retcode or 2 233 retcode = retcode or 2
227 234
228 return retcode 235 return retcode
229 236
230 237
231 if __name__ == '__main__': 238 if __name__ == '__main__':
232 sys.exit(main(sys.argv)) 239 sys.exit(main(sys.argv))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698