Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import ast | 5 import ast |
| 6 import collections | 6 import collections |
| 7 import contextlib | 7 import contextlib |
| 8 import copy | 8 import copy |
| 9 import itertools | 9 import itertools |
| 10 import json | 10 import json |
| 11 | 11 |
| 12 from recipe_engine.types import freeze | 12 from recipe_engine.types import freeze |
| 13 from recipe_engine import recipe_api | 13 from recipe_engine import recipe_api |
| 14 from recipe_engine import util as recipe_util | 14 from recipe_engine import util as recipe_util |
| 15 | 15 |
| 16 from . import bot_config_and_test_db as bdb_module | 16 from . import bot_config_and_test_db as bdb_module |
| 17 from . import builders | 17 from . import builders |
| 18 from . import steps | 18 from . import steps |
| 19 from . import trybots | 19 from . import trybots |
| 20 | 20 |
| 21 | |
|
Sergey Berezin
2016/01/12 01:44:23
nit: please keep 2 blank lines: we separate most t
Ken Russell (switch to Gerrit)
2016/01/12 05:35:51
Sorry, that was an accident.
| |
| 22 MB_CONFIG_FILENAME = ['tools', 'mb', 'mb_config.pyl'] | 21 MB_CONFIG_FILENAME = ['tools', 'mb', 'mb_config.pyl'] |
| 23 | 22 |
| 24 | 23 |
| 25 # Paths which affect recipe config and behavior in a way that survives | 24 # Paths which affect recipe config and behavior in a way that survives |
| 26 # deapplying user's patch. | 25 # deapplying user's patch. |
| 27 RECIPE_CONFIG_PATHS = [ | 26 RECIPE_CONFIG_PATHS = [ |
| 28 'testing/buildbot', | 27 'testing/buildbot', |
| 29 ] | 28 ] |
| 30 | 29 |
| 31 | 30 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 62 return steps | 61 return steps |
| 63 | 62 |
| 64 @property | 63 @property |
| 65 def trybots(self): | 64 def trybots(self): |
| 66 return trybots.TRYBOTS | 65 return trybots.TRYBOTS |
| 67 | 66 |
| 68 def add_builders(self, builders): | 67 def add_builders(self, builders): |
| 69 """Adds builders to our builder map""" | 68 """Adds builders to our builder map""" |
| 70 self._builders.update(builders) | 69 self._builders.update(builders) |
| 71 | 70 |
| 71 def _get_mutable_bot_config(self, mastername, buildername): | |
| 72 master_dict = self.builders.get(mastername, {}) | |
| 73 return master_dict.get('builders', {}).get(buildername) | |
| 74 | |
| 72 def _get_bot_config(self, mastername, buildername): | 75 def _get_bot_config(self, mastername, buildername): |
| 73 master_dict = self.builders.get(mastername, {}) | 76 return freeze(self._get_mutable_bot_config(mastername, buildername)) |
| 74 return freeze(master_dict.get('builders', {}).get(buildername)) | |
| 75 | 77 |
| 76 def configure_build(self, mastername, buildername, override_bot_type=None): | 78 def _get_bot_configs(self, bot_descs): |
| 77 master_dict = self.builders.get(mastername, {}) | 79 bot_configs = [] |
| 78 bot_config = master_dict.get('builders', {}).get(buildername) | 80 for bot_desc in bot_descs: |
| 81 bot_configs.append(self._get_mutable_bot_config(bot_desc['mastername'], | |
| 82 bot_desc['buildername'])) | |
| 83 return bot_configs | |
| 84 | |
| 85 def normalize_bot_descs(self, bot_descs): | |
|
Paweł Hajdan Jr.
2016/01/11 18:41:11
Why do we need this? It's not a very strong prefer
Ken Russell (switch to Gerrit)
2016/01/11 22:54:01
chromium_trybot.py fetches the entry for a tryserv
Sergey Berezin
2016/01/12 01:44:23
This is per my request in the original CL to keep
| |
| 86 """Gets the bot_descs into a uniform format. It should be an array of | |
| 87 dictionary-like objects containing the properties 'mastername' and | |
| 88 'buildername'. | |
| 89 """ | |
| 90 if not isinstance(bot_descs, (list, tuple)): | |
| 91 return [bot_descs] | |
| 92 return bot_descs | |
| 93 | |
| 94 def _verify_property_is_same_across_bot_configs(self, bot_configs, property): | |
| 95 if len(bot_configs) < 2: | |
| 96 return | |
| 97 # This code path is only taken for trybots that mirror more than | |
| 98 # one waterfall bot. Verify that all of the other builders this | |
| 99 # trybot is supposed to mirror all use the same key properties | |
| 100 # like chromium_config and gclient_config. Otherwise, unexpected | |
| 101 # results are likely. | |
| 102 value = bot_configs[0].get(property) | |
| 103 for bot_config in bot_configs[1:]: | |
| 104 if value != bot_config.get(property): | |
| 105 # TODO(kbr): add a test configuration which triggers this error. | |
| 106 # Unclear how difficult it will be. | |
| 107 raise ValueError( | |
| 108 '%s was different between two bots a trybot is mirroring (%s vs %s)' % | |
| 109 (property, value, bot_config.get(value))) # pragma: no cover | |
| 110 | |
| 111 def create_bot_desc(self, mastername, buildername): | |
| 112 """Creates a valid "bot_desc" argument for the various APIs below from | |
| 113 the given mastername and buildername. A dictionary containing the | |
| 114 properties "mastername" and "buildername" is a suitable argument. | |
| 115 An array of such dictionaries is also suitable, in which case tests | |
| 116 will be pulled from multiple testers. | |
|
Sergey Berezin
2016/01/12 01:44:23
The docstring doesnt' make sense to me. It appears
Ken Russell (switch to Gerrit)
2016/01/12 05:35:51
That's true. I should have documented the "bot_des
| |
| 117 """ | |
| 118 return {'mastername': mastername, 'buildername': buildername} | |
| 119 | |
| 120 def configure_build(self, bot_desc, override_bot_type=None): | |
| 121 bot_desc = self.normalize_bot_descs(bot_desc) | |
| 122 bot_configs = self._get_bot_configs(bot_desc) | |
| 79 | 123 |
| 80 # Get the buildspec version. It can be supplied as a build property or as | 124 # Get the buildspec version. It can be supplied as a build property or as |
| 81 # a recipe config value. | 125 # a recipe config value. |
| 82 buildspec_version = (self.m.properties.get('buildspec_version') or | 126 buildspec_version = (self.m.properties.get('buildspec_version') or |
| 83 bot_config.get('buildspec_version')) | 127 bot_configs[0].get('buildspec_version')) |
|
Paweł Hajdan Jr.
2016/01/11 18:41:11
Shouldn't we check that 'buildspec_version' is con
Ken Russell (switch to Gerrit)
2016/01/11 22:54:01
Probably, or at least possibly. I didn't know what
| |
| 128 | |
| 129 self._verify_property_is_same_across_bot_configs(bot_configs, | |
| 130 'chromium_config') | |
| 84 | 131 |
| 85 self.m.chromium.set_config( | 132 self.m.chromium.set_config( |
| 86 bot_config.get('chromium_config'), | 133 bot_configs[0].get('chromium_config'), |
| 87 **bot_config.get('chromium_config_kwargs', {})) | 134 **bot_configs[0].get('chromium_config_kwargs', {})) |
| 88 | 135 |
| 89 # Set GYP_DEFINES explicitly because chromium config constructor does | 136 # Set GYP_DEFINES explicitly because chromium config constructor does |
| 90 # not support that. | 137 # not support that. |
| 91 self.m.chromium.c.gyp_env.GYP_DEFINES.update( | 138 for bot_config in bot_configs: |
| 92 bot_config.get('GYP_DEFINES', {})) | 139 self.m.chromium.c.gyp_env.GYP_DEFINES.update( |
| 93 if bot_config.get('use_isolate'): | 140 bot_config.get('GYP_DEFINES', {})) |
| 94 self.m.isolate.set_isolate_environment(self.m.chromium.c) | 141 if bot_config.get('use_isolate'): |
| 142 self.m.isolate.set_isolate_environment(self.m.chromium.c) | |
| 143 | |
| 144 self._verify_property_is_same_across_bot_configs(bot_configs, | |
| 145 'gclient_config') | |
| 95 | 146 |
| 96 self.m.gclient.set_config( | 147 self.m.gclient.set_config( |
| 97 bot_config.get('gclient_config'), | 148 bot_configs[0].get('gclient_config'), |
| 98 PATCH_PROJECT=self.m.properties.get('patch_project'), | 149 PATCH_PROJECT=self.m.properties.get('patch_project'), |
| 99 BUILDSPEC_VERSION=buildspec_version, | 150 BUILDSPEC_VERSION=buildspec_version, |
| 100 **bot_config.get('gclient_config_kwargs', {})) | 151 **bot_configs[0].get('gclient_config_kwargs', {})) |
|
Sergey Berezin
2016/01/12 01:44:23
Should *_kwargs properties also be checked for bei
Ken Russell (switch to Gerrit)
2016/01/12 05:35:50
Good point. Yes, I think so. (Is this property eve
| |
| 101 | 152 |
| 102 if 'android_config' in bot_config: | 153 if 'android_config' in bot_configs[0]: |
|
Sergey Berezin
2016/01/12 01:44:23
nit: perhaps, more generally:
if any('android_c
Ken Russell (switch to Gerrit)
2016/01/12 05:35:50
Good point.
| |
| 103 self.m.chromium_android.configure_from_properties( | 154 self.m.chromium_android.configure_from_properties( |
| 104 bot_config['android_config'], | 155 bot_configs[0]['android_config'], |
| 105 **bot_config.get('chromium_config_kwargs', {})) | 156 **bot_configs[0].get('chromium_config_kwargs', {})) |
| 157 # This code path hasn't been generalized yet for a trybot that | |
|
Paweł Hajdan Jr.
2016/01/11 18:41:11
Why not a TODO? Also applies to other places which
Ken Russell (switch to Gerrit)
2016/01/11 22:54:01
Yes, these should have TODOs.
| |
| 158 # mirrors multiple bots. | |
| 159 assert len(bot_configs) == 1 | |
| 106 | 160 |
| 107 if 'amp_config' in bot_config: | 161 if 'amp_config' in bot_configs[0]: |
|
Sergey Berezin
2016/01/12 01:44:23
nit: same generalization as above.
Ken Russell (switch to Gerrit)
2016/01/12 05:35:51
Agree.
| |
| 108 self.m.amp.set_config(bot_config['amp_config']) | 162 self.m.amp.set_config(bot_configs[0]['amp_config']) |
| 163 # This code path hasn't been generalized yet for a trybot that | |
| 164 # mirrors multiple bots. | |
| 165 assert len(bot_configs) == 1 | |
| 109 | 166 |
| 110 for c in bot_config.get('chromium_apply_config', []): | 167 chromium_applied_configs = set() |
| 111 self.m.chromium.apply_config(c) | 168 gclient_applied_configs = set() |
| 112 | 169 for bot_config in bot_configs: |
| 113 for c in bot_config.get('gclient_apply_config', []): | 170 for c in bot_config.get('chromium_apply_config', []): |
| 114 self.m.gclient.apply_config(c) | 171 if not c in chromium_applied_configs: |
| 172 self.m.chromium.apply_config(c) | |
| 173 chromium_applied_configs.add(c) | |
| 174 for c in bot_config.get('gclient_apply_config', []): | |
| 175 if not c in gclient_applied_configs: | |
| 176 self.m.gclient.apply_config(c) | |
| 177 gclient_applied_configs.add(c) | |
| 115 | 178 |
| 116 # WARNING: src-side runtest.py is only tested with chromium CQ builders. | 179 # WARNING: src-side runtest.py is only tested with chromium CQ builders. |
| 117 # Usage not covered by chromium CQ is not supported and can break | 180 # Usage not covered by chromium CQ is not supported and can break |
| 118 # without notice. | 181 # without notice. |
| 182 master_dict = self.builders.get(bot_desc[0]['mastername'], {}) | |
|
Paweł Hajdan Jr.
2016/01/11 18:41:11
Why don't we also ensure consistency here?
Ken Russell (switch to Gerrit)
2016/01/11 22:54:01
No good reason not to. This query would be a littl
| |
| 119 if master_dict.get('settings', {}).get('src_side_runtest_py'): | 183 if master_dict.get('settings', {}).get('src_side_runtest_py'): |
| 120 self.m.chromium.c.runtest_py.src_side = True | 184 self.m.chromium.c.runtest_py.src_side = True |
| 121 | 185 |
| 122 if bot_config.get('goma_canary'): | 186 if bot_configs[0].get('goma_canary'): |
|
Sergey Berezin
2016/01/12 01:44:23
nit: same generalization as above.
Ken Russell (switch to Gerrit)
2016/01/12 05:35:51
Acknowledged.
| |
| 123 self.m.goma.update_goma_canary(buildername) | 187 self.m.goma.update_goma_canary(bot_desc[0]['buildername']) |
| 188 # This code path hasn't been generalized yet for a trybot that | |
| 189 # mirrors multiple bots. | |
| 190 assert len(bot_configs) == 1 | |
| 124 | 191 |
| 125 bot_type = override_bot_type or bot_config.get('bot_type', 'builder_tester') | 192 bot_type = override_bot_type or bot_configs[0].get('bot_type', |
|
Sergey Berezin
2016/01/12 01:44:23
nit: move inside the 'if'. This var is only used i
Ken Russell (switch to Gerrit)
2016/01/12 05:35:51
Good point.
| |
| 193 'builder_tester') | |
| 126 | 194 |
| 127 if bot_config.get('set_component_rev'): | 195 if bot_configs[0].get('set_component_rev'): |
|
Sergey Berezin
2016/01/12 01:44:23
nit: same generalization as above.
Ken Russell (switch to Gerrit)
2016/01/12 05:35:51
Acknowledged.
| |
| 128 # If this is a component build and the main revision is e.g. blink, | 196 # If this is a component build and the main revision is e.g. blink, |
| 129 # webrtc, or v8, the custom deps revision of this component must be | 197 # webrtc, or v8, the custom deps revision of this component must be |
| 130 # dynamically set to either: | 198 # dynamically set to either: |
| 131 # (1) the revision of the builder if this is a tester, | 199 # (1) the revision of the builder if this is a tester, |
| 132 # (2) 'revision' from the waterfall, or | 200 # (2) 'revision' from the waterfall, or |
| 133 # (3) 'HEAD' for forced builds with unspecified 'revision'. | 201 # (3) 'HEAD' for forced builds with unspecified 'revision'. |
| 134 # TODO(machenbach): Use parent_got_cr_revision on testers with component | 202 # TODO(machenbach): Use parent_got_cr_revision on testers with component |
| 135 # builds to match also the chromium revision from the builder. | 203 # builds to match also the chromium revision from the builder. |
| 136 component_rev = self.m.properties.get('revision') or 'HEAD' | 204 component_rev = self.m.properties.get('revision') or 'HEAD' |
| 137 if bot_type == 'tester': | 205 if bot_type == 'tester': |
| 138 component_rev = self.m.properties.get( | 206 component_rev = self.m.properties.get( |
| 139 'parent_got_revision', component_rev) | 207 'parent_got_revision', component_rev) |
| 140 dep = bot_config.get('set_component_rev') | 208 dep = bot_configs[0].get('set_component_rev') |
| 141 self.m.gclient.c.revisions[dep['name']] = dep['rev_str'] % component_rev | 209 self.m.gclient.c.revisions[dep['name']] = dep['rev_str'] % component_rev |
| 210 # This code path hasn't been generalized yet for a trybot that | |
| 211 # mirrors multiple bots. | |
| 212 assert len(bot_configs) == 1 | |
| 142 | 213 |
| 143 def ensure_checkout(self, mastername, buildername, | 214 def ensure_checkout(self, mastername, buildername, |
| 144 root_solution_revision=None): | 215 root_solution_revision=None): |
| 145 bot_config = self._get_bot_config(mastername, buildername) | 216 bot_config = self._get_bot_config(mastername, buildername) |
| 146 | 217 |
| 147 if self.m.platform.is_win: | 218 if self.m.platform.is_win: |
| 148 self.m.chromium.taskkill() | 219 self.m.chromium.taskkill() |
| 149 | 220 |
| 150 # Bot Update re-uses the gclient configs. | 221 # Bot Update re-uses the gclient configs. |
| 151 update_step = self.m.bot_update.ensure_checkout( | 222 update_step = self.m.bot_update.ensure_checkout( |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 172 if self.m.tryserver.is_tryserver: | 243 if self.m.tryserver.is_tryserver: |
| 173 try: | 244 try: |
| 174 self.m.chromium.runhooks(name='runhooks (with patch)') | 245 self.m.chromium.runhooks(name='runhooks (with patch)') |
| 175 except self.m.step.StepFailure: | 246 except self.m.step.StepFailure: |
| 176 # As part of deapplying patch we call runhooks without the patch. | 247 # As part of deapplying patch we call runhooks without the patch. |
| 177 self.deapply_patch(update_step) | 248 self.deapply_patch(update_step) |
| 178 raise | 249 raise |
| 179 else: | 250 else: |
| 180 self.m.chromium.runhooks() | 251 self.m.chromium.runhooks() |
| 181 | 252 |
| 182 def get_test_spec(self, mastername, buildername): | 253 def get_test_spec(self, mastername, buildername, |
| 254 annotate_master_name=False): | |
| 183 bot_config = self._get_bot_config(mastername, buildername) | 255 bot_config = self._get_bot_config(mastername, buildername) |
| 184 | 256 |
| 185 test_spec_file = bot_config.get('testing', {}).get( | 257 test_spec_file = bot_config.get('testing', {}).get( |
| 186 'test_spec_file', '%s.json' % mastername) | 258 'test_spec_file', '%s.json' % mastername) |
| 187 | 259 |
| 188 # TODO(phajdan.jr): Bots should have no generators instead. | 260 # TODO(phajdan.jr): Bots should have no generators instead. |
| 189 if bot_config.get('disable_tests'): | 261 if bot_config.get('disable_tests'): |
| 190 return {} | 262 return {} |
| 191 return self.read_test_spec(self.m, test_spec_file) | 263 return self.read_test_spec(self.m, test_spec_file, |
| 264 annotate_master_name=annotate_master_name, | |
| 265 master_name_for_annotation=mastername) | |
| 192 | 266 |
| 193 def _get_master_dict_with_dynamic_tests( | 267 def _get_master_dict_with_dynamic_tests( |
| 194 self, mastername, buildername, test_spec, scripts_compile_targets): | 268 self, mastername, buildername, test_spec, scripts_compile_targets): |
| 195 # We manually thaw the path to the elements we are modifying, since the | 269 # We manually thaw the path to the elements we are modifying, since the |
| 196 # builders are frozen. | 270 # builders are frozen. |
| 197 master_dict = dict(self.builders[mastername]) | 271 master_dict = dict(self.builders[mastername]) |
| 198 builders = master_dict['builders'] = dict(master_dict['builders']) | 272 builders = master_dict['builders'] = dict(master_dict['builders']) |
| 199 bot_config = builders[buildername] | 273 bot_config = builders[buildername] |
| 200 for loop_buildername in builders: | 274 for loop_buildername in builders: |
| 201 builder_dict = builders[loop_buildername] = ( | 275 builder_dict = builders[loop_buildername] = ( |
| 202 dict(builders[loop_buildername])) | 276 dict(builders[loop_buildername])) |
| 203 builders[loop_buildername]['tests'] = ( | 277 builders[loop_buildername]['tests'] = ( |
| 204 self.generate_tests_from_test_spec( | 278 self.generate_tests_from_test_spec( |
| 205 self.m, test_spec, builder_dict, loop_buildername, mastername, | 279 self.m, test_spec, builder_dict, loop_buildername, mastername, |
| 206 # TODO(phajdan.jr): Get enable_swarming value from builder_dict. | 280 # TODO(phajdan.jr): Get enable_swarming value from builder_dict. |
| 207 # Above should remove the need to get bot_config and buildername | 281 # Above should remove the need to get bot_config and buildername |
| 208 # in this method. | 282 # in this method. |
| 209 bot_config.get('enable_swarming', False), | 283 bot_config.get('enable_swarming', False), |
| 210 scripts_compile_targets, builder_dict.get('test_generators', []) | 284 scripts_compile_targets, builder_dict.get('test_generators', []) |
| 211 )) | 285 )) |
| 212 | 286 |
| 213 return freeze(master_dict) | 287 return freeze(master_dict) |
| 214 | 288 |
| 215 def create_bot_db_from_master_dict(self, mastername, master_dict): | 289 def create_bot_db_from_master_dict(self, mastername, master_dict): |
| 216 bot_db = bdb_module.BotConfigAndTestDB() | 290 bot_db = bdb_module.BotConfigAndTestDB() |
| 217 bot_db._add_master_dict_and_test_spec(mastername, master_dict, {}) | 291 bot_db._add_master_dict_and_test_spec(mastername, master_dict, {}) |
| 218 return bot_db | 292 return bot_db |
| 219 | 293 |
| 220 def prepare_checkout(self, mastername, buildername, | 294 def prepare_checkout(self, bot_desc, root_solution_revision=None): |
| 221 root_solution_revision=None): | 295 bot_desc = self.normalize_bot_descs(bot_desc) |
| 222 bot_config = self._get_bot_config(mastername, buildername) | 296 bot_configs = self._get_bot_configs(bot_desc) |
| 223 | 297 |
| 224 update_step = self.ensure_checkout(mastername, buildername, | 298 # Use the first bot's mastername and buildername for several of |
| 299 # the setup steps in this routine. | |
| 300 mastername = bot_desc[0]['mastername'] | |
| 301 buildername = bot_desc[0]['buildername'] | |
| 302 | |
| 303 update_step = self.ensure_checkout(mastername, | |
| 304 buildername, | |
| 225 root_solution_revision) | 305 root_solution_revision) |
| 226 # TODO(robertocn): Remove this hack by the end of Q1/2016. | 306 # TODO(robertocn): Remove this hack by the end of Q1/2016. |
| 227 if (mastername == 'tryserver.chromium.perf' | 307 if (mastername == 'tryserver.chromium.perf' |
| 228 and bot_config.get('bot_type') == 'builder' | 308 and bot_configs[0].get('bot_type') == 'builder' |
|
Sergey Berezin
2016/01/12 01:44:23
nit: perhaps, also generalize as above?
Ken Russell (switch to Gerrit)
2016/01/12 05:35:50
Maybe. Since this is a hack it might be best to to
| |
| 229 and buildername.endswith('builder')): | 309 and buildername.endswith('builder')): |
| 230 force_legacy_compile = self.should_force_legacy_compiling( | 310 force_legacy_compile = self.should_force_legacy_compiling( |
| 231 mastername, buildername) | 311 mastername, buildername) |
| 232 if force_legacy_compile: | 312 if force_legacy_compile: |
| 233 self.m.chromium.c.project_generator.tool = 'gyp' | 313 self.m.chromium.c.project_generator.tool = 'gyp' |
| 314 # This code path hasn't been generalized yet for a trybot that | |
| 315 # mirrors multiple bots. | |
| 316 assert len(bot_configs) == 1 | |
| 234 | 317 |
| 235 self.set_up_swarming(mastername, buildername) | 318 self.set_up_swarming(mastername, buildername) |
| 236 self.runhooks(update_step) | 319 self.runhooks(update_step) |
| 237 | 320 |
| 238 test_spec = self.get_test_spec(mastername, buildername) | 321 bot_db = bdb_module.BotConfigAndTestDB() |
| 239 | 322 |
| 240 # TODO(phajdan.jr): Bots should have no generators instead. | 323 scripts_compile_targets = {} |
| 241 if bot_config.get('disable_tests'): | 324 first_iteration = True |
| 242 scripts_compile_targets = {} | |
| 243 else: | |
| 244 scripts_compile_targets = \ | |
| 245 self.get_compile_targets_for_scripts().json.output | |
| 246 | 325 |
| 247 master_dict = self._get_master_dict_with_dynamic_tests( | 326 for bot in bot_desc: |
| 248 mastername, buildername, test_spec, scripts_compile_targets) | 327 test_spec = self.get_test_spec( |
| 328 bot['mastername'], bot['buildername'], | |
| 329 annotate_master_name=not first_iteration) | |
| 330 | |
| 331 # This is done this way to reduce test expectation changes. | |
| 332 if first_iteration: | |
| 333 # TODO(phajdan.jr): Bots should have no generators instead. | |
| 334 if bot_configs[0].get('disable_tests'): | |
| 335 scripts_compile_targets = {} | |
| 336 else: | |
| 337 scripts_compile_targets = \ | |
| 338 self.get_compile_targets_for_scripts().json.output | |
| 339 first_iteration = False | |
| 340 | |
| 341 master_dict = self._get_master_dict_with_dynamic_tests( | |
| 342 bot['mastername'], bot['buildername'], test_spec, | |
| 343 scripts_compile_targets) | |
| 344 bot_db._add_master_dict_and_test_spec( | |
| 345 bot['mastername'], master_dict, test_spec) | |
| 249 | 346 |
| 250 if self.m.chromium.c.lto and \ | 347 if self.m.chromium.c.lto and \ |
| 251 not self.m.chromium.c.env.LLVM_FORCE_HEAD_REVISION: | 348 not self.m.chromium.c.env.LLVM_FORCE_HEAD_REVISION: |
| 252 self.m.chromium.download_lto_plugin() | 349 self.m.chromium.download_lto_plugin() |
| 253 | 350 |
| 254 bot_db = bdb_module.BotConfigAndTestDB() | |
| 255 bot_db._add_master_dict_and_test_spec(mastername, master_dict, test_spec) | |
| 256 | |
| 257 return update_step, bot_db | 351 return update_step, bot_db |
| 258 | 352 |
| 259 def generate_tests_from_test_spec(self, api, test_spec, builder_dict, | 353 def generate_tests_from_test_spec(self, api, test_spec, builder_dict, |
| 260 buildername, mastername, enable_swarming, scripts_compile_targets, | 354 buildername, mastername, enable_swarming, scripts_compile_targets, |
| 261 generators): | 355 generators): |
| 262 tests = builder_dict.get('tests', ()) | 356 tests = builder_dict.get('tests', ()) |
| 263 # TODO(phajdan.jr): Switch everything to scripts generators and simplify. | 357 # TODO(phajdan.jr): Switch everything to scripts generators and simplify. |
| 264 for generator in generators: | 358 for generator in generators: |
| 265 tests = ( | 359 tests = ( |
| 266 tuple(generator(api, mastername, buildername, test_spec, | 360 tuple(generator(api, mastername, buildername, test_spec, |
| 267 enable_swarming=enable_swarming, | 361 enable_swarming=enable_swarming, |
| 268 scripts_compile_targets=scripts_compile_targets)) + | 362 scripts_compile_targets=scripts_compile_targets)) + |
| 269 tests) | 363 tests) |
| 270 return tests | 364 return tests |
| 271 | 365 |
| 272 def read_test_spec(self, api, test_spec_file): | 366 def read_test_spec(self, api, test_spec_file, annotate_master_name=False, |
| 367 master_name_for_annotation=None): | |
| 273 test_spec_path = api.path['checkout'].join('testing', 'buildbot', | 368 test_spec_path = api.path['checkout'].join('testing', 'buildbot', |
| 274 test_spec_file) | 369 test_spec_file) |
| 370 step_name = 'read test spec' | |
| 371 if annotate_master_name: | |
| 372 step_name += ' (%s)' % master_name_for_annotation | |
| 275 test_spec_result = api.json.read( | 373 test_spec_result = api.json.read( |
| 276 'read test spec', | 374 step_name, |
| 277 test_spec_path, | 375 test_spec_path, |
| 278 step_test_data=lambda: api.json.test_api.output({})) | 376 step_test_data=lambda: api.json.test_api.output({})) |
| 279 test_spec_result.presentation.step_text = 'path: %s' % test_spec_path | 377 test_spec_result.presentation.step_text = 'path: %s' % test_spec_path |
| 280 test_spec = test_spec_result.json.output | 378 test_spec = test_spec_result.json.output |
| 281 | 379 |
| 282 return test_spec | 380 return test_spec |
| 283 | 381 |
| 284 def create_test_runner(self, api, tests, suffix=''): | 382 def create_test_runner(self, api, tests, suffix=''): |
| 285 """Creates a test runner to run a set of tests. | 383 """Creates a test runner to run a set of tests. |
| 286 | 384 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 raise | 423 raise |
| 326 | 424 |
| 327 if failed_tests: | 425 if failed_tests: |
| 328 failed_tests_names = [t.name for t in failed_tests] | 426 failed_tests_names = [t.name for t in failed_tests] |
| 329 raise self.m.step.StepFailure( | 427 raise self.m.step.StepFailure( |
| 330 '%d tests failed: %r' % (len(failed_tests), failed_tests_names)) | 428 '%d tests failed: %r' % (len(failed_tests), failed_tests_names)) |
| 331 | 429 |
| 332 return test_runner | 430 return test_runner |
| 333 | 431 |
| 334 def get_compile_targets_and_tests( | 432 def get_compile_targets_and_tests( |
| 433 self, bot_desc, bot_db, override_bot_type=None, override_tests=None): | |
| 434 bot_desc = self.normalize_bot_descs(bot_desc) | |
| 435 """Returns a tuple: list of compile targets and list of tests. | |
| 436 | |
| 437 The list of tests includes ones on the triggered testers.""" | |
| 438 all_compile_targets = set() | |
| 439 all_tests = [] | |
| 440 for bot in bot_desc: | |
| 441 compile_targets, tests = self._get_single_bot_compile_targets_and_tests( | |
| 442 bot['mastername'], bot['buildername'], bot_db, | |
| 443 override_bot_type=override_bot_type, override_tests=override_tests) | |
| 444 all_compile_targets.update(compile_targets) | |
| 445 # It doesn't seem feasible to de-duplicate tests in the case where | |
| 446 # a tryserver mirrors multiple waterfall bots. (This is the only | |
| 447 # case where there's more than one entry in bot_configs.) Just add | |
| 448 # them all in the order returned. | |
| 449 all_tests.extend(tests) | |
| 450 # The incoming 'override_tests' must be reset during the second | |
|
Paweł Hajdan Jr.
2016/01/11 18:41:11
Why don't we override tests at the end?
The curre
Ken Russell (switch to Gerrit)
2016/01/11 22:54:01
Good point; that's probably the correct thing to d
| |
| 451 # and subsequent loop iterations, or trybots which mirror multiple | |
| 452 # bots will add the same set of tests multiple times. | |
| 453 # TODO(kbr): it isn't clear to me what the correct behavior is here. | |
| 454 # What should happen with the second bot's 'tests' property? | |
| 455 override_tests = None | |
| 456 | |
| 457 return sorted(all_compile_targets), all_tests | |
| 458 | |
| 459 def _get_single_bot_compile_targets_and_tests( | |
| 335 self, mastername, buildername, bot_db, | 460 self, mastername, buildername, bot_db, |
| 336 override_bot_type=None, override_tests=None): | 461 override_bot_type=None, override_tests=None): |
| 337 """Returns a tuple: list of compile targets and list of tests. | 462 """Returns a tuple: list of compile targets and list of tests. |
| 338 | 463 |
| 339 The list of tests includes ones on the triggered testers.""" | 464 The list of tests includes ones on the triggered testers.""" |
| 340 | 465 |
| 341 assert isinstance(bot_db, bdb_module.BotConfigAndTestDB), \ | 466 assert isinstance(bot_db, bdb_module.BotConfigAndTestDB), \ |
| 342 "bot_db argument %r was not a BotConfigAndTestDB" % (bot_db) | 467 "bot_db argument %r was not a BotConfigAndTestDB" % (bot_db) |
| 343 bot_config = bot_db.get_bot_config(mastername, buildername) | 468 bot_config = bot_db.get_bot_config(mastername, buildername) |
| 344 bot_type = override_bot_type or bot_config.get('bot_type', 'builder_tester') | 469 bot_type = override_bot_type or bot_config.get('bot_type', 'builder_tester') |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 384 try: | 509 try: |
| 385 command(lambda name: '%s (with patch)' % name) | 510 command(lambda name: '%s (with patch)' % name) |
| 386 except self.m.step.StepFailure: | 511 except self.m.step.StepFailure: |
| 387 self.deapply_patch(update_step) | 512 self.deapply_patch(update_step) |
| 388 command(lambda name: '%s (without patch)' % name) | 513 command(lambda name: '%s (without patch)' % name) |
| 389 raise | 514 raise |
| 390 else: | 515 else: |
| 391 command(lambda name: name) | 516 command(lambda name: name) |
| 392 | 517 |
| 393 | 518 |
| 394 def compile(self, mastername, buildername, update_step, bot_db, | 519 def compile(self, bot_desc, update_step, bot_db, |
| 395 mb_mastername=None, mb_buildername=None): | 520 mb_mastername=None, mb_buildername=None): |
| 396 """Runs compile and related steps for given builder.""" | 521 """Runs compile and related steps for builder(s) described in bot_desc.""" |
| 522 bot_desc = self.normalize_bot_descs(bot_desc) | |
| 397 assert isinstance(bot_db, bdb_module.BotConfigAndTestDB), \ | 523 assert isinstance(bot_db, bdb_module.BotConfigAndTestDB), \ |
| 398 "bot_db argument %r was not a BotConfigAndTestDB" % (bot_db) | 524 "bot_db argument %r was not a BotConfigAndTestDB" % (bot_db) |
| 399 compile_targets, tests_including_triggered = \ | 525 compile_targets, tests_including_triggered = \ |
| 400 self.get_compile_targets_and_tests( | 526 self.get_compile_targets_and_tests( |
| 401 mastername, | 527 bot_desc, |
| 402 buildername, | |
| 403 bot_db) | 528 bot_db) |
| 404 self.compile_specific_targets( | 529 self.compile_specific_targets( |
| 405 mastername, buildername, update_step, bot_db, | 530 bot_desc[0]['mastername'], bot_desc[0]['buildername'], |
|
Sergey Berezin
2016/01/12 01:44:23
Shouldn't we compile for all bot_descs? E.g. this
Ken Russell (switch to Gerrit)
2016/01/12 05:35:51
At first glance it didn't seem necessary to genera
| |
| 406 compile_targets, tests_including_triggered, | 531 update_step, bot_db, compile_targets, tests_including_triggered, |
| 407 mb_mastername=mb_mastername, mb_buildername=mb_buildername) | 532 mb_mastername=mb_mastername, mb_buildername=mb_buildername) |
| 408 | 533 |
| 409 def compile_specific_targets( | 534 def compile_specific_targets( |
| 410 self, mastername, buildername, update_step, bot_db, | 535 self, mastername, buildername, update_step, bot_db, |
| 411 compile_targets, tests_including_triggered, | 536 compile_targets, tests_including_triggered, |
| 412 mb_mastername=None, mb_buildername=None, override_bot_type=None): | 537 mb_mastername=None, mb_buildername=None, override_bot_type=None): |
| 413 """Runs compile and related steps for given builder. | 538 """Runs compile and related steps for given builder. |
| 414 | 539 |
| 415 Allows finer-grained control about exact compile targets used. | 540 Allows finer-grained control about exact compile targets used. |
| 416 | 541 |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 893 result_text = 'MB is enabled for this builder at this revision.' | 1018 result_text = 'MB is enabled for this builder at this revision.' |
| 894 log_name = 'Builder MB-ready' | 1019 log_name = 'Builder MB-ready' |
| 895 self.m.step.active_result.presentation.logs[log_name] = [result_text] | 1020 self.m.step.active_result.presentation.logs[log_name] = [result_text] |
| 896 return False | 1021 return False |
| 897 except (self.m.step.StepFailure, KeyError): | 1022 except (self.m.step.StepFailure, KeyError): |
| 898 result_text = 'MB is not enabled for this builder at this revision.' | 1023 result_text = 'MB is not enabled for this builder at this revision.' |
| 899 log_name = 'Builder NOT MB-ready' | 1024 log_name = 'Builder NOT MB-ready' |
| 900 self.m.step.active_result.presentation.logs[log_name] = [result_text] | 1025 self.m.step.active_result.presentation.logs[log_name] = [result_text] |
| 901 self.m.step.active_result.presentation.status = self.m.step.WARNING | 1026 self.m.step.active_result.presentation.status = self.m.step.WARNING |
| 902 return True | 1027 return True |
| OLD | NEW |