| # Copyright 2016 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import json |
| |
| from recipe_engine import recipe_test_api |
| |
| |
| class RecipeAutorollerTestApi(recipe_test_api.RecipeTestApi): |
| _TBR_EMAILS = ('foo@bar.example.com', 'meep@example.com') |
| _EXTRA_REVIEWERS = ('foo@chromium.org', 'foo@bar.example.com', |
| 'meep@example.com') |
| |
| def repo_spec(self, |
| tbr_emails=_TBR_EMAILS, |
| extra_reviewers=_EXTRA_REVIEWERS, |
| disable_reason='', |
| self_approve_method='BOT_COMMIT_APPROVE', |
| trivial_commit=True, |
| trivial_dryrun=False, |
| nontrivial_dryrun=True, |
| nontrivial_autosubmit=True, |
| include_autoroll_options=True, |
| no_cc_authors=False): |
| spec = { |
| 'api_version': 2, |
| 'deps': { |
| 'recipe_engine': { |
| 'url': |
| 'https://chromium.googlesource.com/infra/luci/recipes-py', |
| }, |
| }, |
| } |
| if include_autoroll_options: |
| spec['autoroll_recipe_options'] = { |
| 'trivial': { |
| 'tbr_emails': list(tbr_emails), |
| 'automatic_commit': trivial_commit, |
| 'dry_run': trivial_dryrun, |
| 'self_approve_method': self_approve_method, |
| }, |
| 'nontrivial': { |
| 'extra_reviewer_emails': list(extra_reviewers), |
| 'automatic_commit_dry_run': nontrivial_dryrun, |
| 'set_autosubmit': nontrivial_autosubmit, |
| }, |
| 'disable_reason': disable_reason, |
| 'no_cc_authors': no_cc_authors, |
| } |
| return spec |
| |
| def roll_data(self, |
| project, |
| spec=None, |
| success=True, |
| trivial=True, |
| empty=False, |
| num_commits=1): |
| """Returns mock roll and recipes.cfg data for |project|.""" |
| if spec is None: |
| spec = self.repo_spec() |
| if empty: |
| success = False |
| |
| ret = self.empty_test_data() + self.recipe_cfg(project, spec) |
| if spec.get('autoroll_recipe_options', {}).get('disable_reason'): |
| return ret |
| |
| commit_infos = [] |
| for i in range(num_commits): |
| commit_infos.append({ |
| 'author_email': 'foo@chromium.org', |
| 'message_lines': [ |
| ('some commit summary that is too long to fit in a single ' |
| 'line in Gerrit'), |
| ('R=bar@chromium.org,baz@chromium.org,invalid1,' |
| 'invalid2@chromium'), |
| 'BUG=123,456', |
| ], |
| 'revision': '%d23abc' % (i + 1), |
| }) |
| |
| picked_roll_details = { |
| 'commit_infos': { |
| 'recipe_engine': commit_infos, |
| }, |
| 'spec': spec, |
| } |
| |
| roll_result = { |
| 'success': success, |
| 'trivial': trivial if success else None, |
| 'picked_roll_details': picked_roll_details if success else None, |
| } |
| roll_result['rejected_candidates_count'] = 0 |
| if empty: |
| roll_result['roll_details'] = [] |
| else: |
| roll_result['roll_details'] = [picked_roll_details] |
| if not success: |
| roll_result['rejected_candidates_count'] = 1 |
| |
| ret += self.step_data('%s.roll' % project, self.m.json.output(roll_result)) |
| return ret |
| |
| def repo_data(self, project, trivial, status, timestamp): |
| return (self.override_step_data( |
| '%s.gsutil repo_state' % project, |
| self.m.raw_io.stream_output_text( |
| json.dumps({ |
| 'issue': '123456789', |
| 'issue_url': 'https://codereview.chromium.org/123456789', |
| 'trivial': trivial, |
| 'last_roll_ts_utc': timestamp, |
| }), |
| stream='stdout'), |
| self.m.raw_io.stream_output_text('', stream='stderr')) + |
| self.step_data('%s.git cl status' % project, |
| self.m.raw_io.stream_output_text(status))) |
| |
| def recipe_cfg(self, project, spec=None): |
| """Returns mock recipes.cfg data (only) for |project|. |
| |
| This is used for tests which abort between the 'read recipes.cfg' step and |
| the 'roll' step (e.g. which read repo state and decide to quit early). |
| |
| For "normal" test runs, you'll want to use roll_data() from this |
| RecipeTestApi, which includes this step data automatically. |
| """ |
| if spec is None: |
| spec = self.repo_spec() |
| return self.override_step_data( |
| '%s.read recipes.cfg' % project, self.m.json.output(spec) |
| ) |