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

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

Issue 1111413005: Some changes to allow recipes and modules to live noncentrally (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Review comments Created 5 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 | Annotate | Revision Log
« no previous file with comments | « scripts/slave/recipes/chromium_gn.py ('k') | scripts/slave/unittests/recipe_lint.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 25 matching lines...) Expand all
36 for x in recipe_util.MODULE_DIRS()], 36 for x in recipe_util.MODULE_DIRS()],
37 data_file='.recipe_configs_test_coverage', data_suffix=True))() 37 data_file='.recipe_configs_test_coverage', data_suffix=True))()
38 38
39 def covered(fn, *args, **kwargs): 39 def covered(fn, *args, **kwargs):
40 COVERAGE.start() 40 COVERAGE.start()
41 try: 41 try:
42 return fn(*args, **kwargs) 42 return fn(*args, **kwargs)
43 finally: 43 finally:
44 COVERAGE.stop() 44 COVERAGE.stop()
45 45
46 UNIVERSE = recipe_loader.RecipeUniverse()
47
48 def load_recipe_modules():
49 modules = {}
50 for modpath in recipe_loader.loop_over_recipe_modules():
51 # That's right, we're using the path as the local name! The local
52 # name really could be anything unique, we don't use it.
53 modules[modpath] = UNIVERSE.load(recipe_loader.PathDependency(
54 modpath, local_name=modpath, base_path=os.curdir))
55 return modules
56
57
46 RECIPE_MODULES = None 58 RECIPE_MODULES = None
47 def init_recipe_modules(): 59 def init_recipe_modules():
48 global RECIPE_MODULES 60 global RECIPE_MODULES
49 RECIPE_MODULES = covered(recipe_loader.load_recipe_modules, 61 RECIPE_MODULES = covered(load_recipe_modules)
50 recipe_util.MODULE_DIRS())
51 62
52 from slave import recipe_config # pylint: disable=F0401 63 from slave import recipe_config # pylint: disable=F0401
53 64
54 65
55 def evaluate_configurations(args): 66 def evaluate_configurations(args):
56 mod_id, var_assignments = args 67 mod_id, var_assignments = args
57 mod = getattr(RECIPE_MODULES, mod_id) 68 mod = RECIPE_MODULES[mod_id]
58 ctx = mod.CONFIG_CTX 69 ctx = mod.CONFIG_CTX
59 70
60 config_name = None 71 config_name = None
61 try: 72 try:
62 make_item = lambda: covered(ctx.CONFIG_SCHEMA, **var_assignments) 73 make_item = lambda: covered(ctx.CONFIG_SCHEMA, **var_assignments)
63 74
64 # Try ROOT_CONFIG_ITEM first. If it raises BadConf, then we can skip 75 # Try ROOT_CONFIG_ITEM first. If it raises BadConf, then we can skip
65 # this config. 76 # this config.
66 root_item = ctx.ROOT_CONFIG_ITEM 77 root_item = ctx.ROOT_CONFIG_ITEM
67 if root_item: 78 if root_item:
(...skipping 16 matching lines...) Expand all
84 pass # This is a possibly expected failure mode. 95 pass # This is a possibly expected failure mode.
85 return True 96 return True
86 except Exception as e: 97 except Exception as e:
87 print ('Caught unknown exception [%s] for config name [%s] for module ' 98 print ('Caught unknown exception [%s] for config name [%s] for module '
88 '[%s] with args %s') % (e, config_name, mod_id, var_assignments) 99 '[%s] with args %s') % (e, config_name, mod_id, var_assignments)
89 traceback.print_exc() 100 traceback.print_exc()
90 return False 101 return False
91 102
92 103
93 def multiprocessing_init(): 104 def multiprocessing_init():
94 init_recipe_modules()
95
96 # HACK: multiprocessing doesn't work with atexit, so shim the exit functions 105 # HACK: multiprocessing doesn't work with atexit, so shim the exit functions
97 # instead. This allows us to save exactly one coverage file per subprocess. 106 # instead. This allows us to save exactly one coverage file per subprocess.
98 # pylint: disable=W0212 107 # pylint: disable=W0212
99 real_os_exit = multiprocessing.forking.exit 108 real_os_exit = multiprocessing.forking.exit
100 def exitfn(code): 109 def exitfn(code):
101 COVERAGE.save() 110 COVERAGE.save()
102 real_os_exit(code) 111 real_os_exit(code)
103 multiprocessing.forking.exit = exitfn 112 multiprocessing.forking.exit = exitfn
104 113
105 # This check mirrors the logic in multiprocessing.forking.exit 114 # This check mirrors the logic in multiprocessing.forking.exit
106 if sys.platform != 'win32': 115 if sys.platform != 'win32':
107 # Even though multiprocessing.forking.exit is defined, it's not used in the 116 # Even though multiprocessing.forking.exit is defined, it's not used in the
108 # non-win32 version of multiprocessing.forking.Popen... *loss for words* 117 # non-win32 version of multiprocessing.forking.Popen... *loss for words*
109 os._exit = exitfn 118 os._exit = exitfn
110 119
111 120
112 def coverage_parallel_map(fn): 121 def coverage_parallel_map(fn):
113 combination_generator = ( 122 combination_generator = (
114 (mod_id, var_assignments) 123 (mod_id, var_assignments)
115 for mod_id, mod in RECIPE_MODULES.__dict__.iteritems() 124 for mod_id, mod in RECIPE_MODULES.iteritems()
116 if mod_id[0] != '_' and mod.CONFIG_CTX 125 if mod.CONFIG_CTX
117 for var_assignments in imap(dict, product(*[ 126 for var_assignments in imap(dict, product(*[
118 [(key_name, val) for val in vals] 127 [(key_name, val) for val in vals]
119 for key_name, vals in mod.CONFIG_CTX.VAR_TEST_MAP.iteritems() 128 for key_name, vals in mod.CONFIG_CTX.VAR_TEST_MAP.iteritems()
120 ])) 129 ]))
121 ) 130 )
122 131
123 pool = multiprocessing.Pool(initializer=multiprocessing_init) 132 pool = multiprocessing.Pool(initializer=multiprocessing_init)
124 try: 133 try:
125 return pool.map_async(fn, combination_generator).get(999999) 134 return pool.map_async(fn, combination_generator).get(999999)
126 finally: 135 finally:
(...skipping 16 matching lines...) Expand all
143 if not success: 152 if not success:
144 print 'FATAL: Some recipe configuration(s) failed' 153 print 'FATAL: Some recipe configuration(s) failed'
145 if not all_covered: 154 if not all_covered:
146 print 'FATAL: Recipes configs are not at 100% coverage.' 155 print 'FATAL: Recipes configs are not at 100% coverage.'
147 156
148 return 1 if (not success or not all_covered) else 0 157 return 1 if (not success or not all_covered) else 0
149 158
150 159
151 if __name__ == '__main__': 160 if __name__ == '__main__':
152 sys.exit(main()) 161 sys.exit(main())
OLDNEW
« no previous file with comments | « scripts/slave/recipes/chromium_gn.py ('k') | scripts/slave/unittests/recipe_lint.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698