| # 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 blinkpy.common.host_mock import MockHost |
| from blinkpy.common.system.log_testing import LoggingTestCase |
| from blinkpy.w3c.chromium_commit_mock import MockChromiumCommit |
| from blinkpy.w3c.gerrit import GerritError |
| from blinkpy.w3c.gerrit_mock import MockGerritAPI, MockGerritCL |
| from blinkpy.w3c.test_exporter import TestExporter |
| from blinkpy.w3c.wpt_github import PullRequest |
| from blinkpy.w3c.wpt_github_mock import MockWPTGitHub |
| |
| |
| class TestExporterTest(LoggingTestCase): |
| def setUp(self): |
| super(TestExporterTest, self).setUp() |
| host = MockHost() |
| host.filesystem.write_text_file( |
| '/tmp/credentials.json', |
| json.dumps({ |
| 'GH_USER': 'github-username', |
| 'GH_TOKEN': 'github-token', |
| 'GERRIT_USER': 'gerrit-username', |
| 'GERRIT_TOKEN': 'gerrit-token', |
| })) |
| self.host = host |
| |
| def test_dry_run_stops_before_creating_pr(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[ |
| PullRequest( |
| title='title1', number=1234, body='', state='open', labels=[]), |
| ]) |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.gerrit.exportable_open_cls = [ |
| MockGerritCL( |
| data={ |
| 'change_id': 'I001', |
| 'subject': 'subject', |
| '_number': 1234, |
| 'current_revision': '1', |
| 'has_review_started': True, |
| 'revisions': { |
| '1': { |
| 'commit_with_footers': 'a commit with footers' |
| } |
| }, |
| 'owner': { |
| 'email': 'test@chromium.org' |
| }, |
| }, |
| api=test_exporter.gerrit, |
| chromium_commit=MockChromiumCommit( |
| self.host, |
| subject='subject', |
| body='fake body', |
| change_id='I001')) |
| ] |
| test_exporter.get_exportable_commits = lambda: ([ |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#458475}'), |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#458476}'), |
| ], []) |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json', '--dry-run']) |
| |
| self.assertTrue(success) |
| self.assertEqual(test_exporter.wpt_github.calls, [ |
| 'pr_with_change_id', |
| 'pr_for_chromium_commit', |
| 'pr_for_chromium_commit', |
| ]) |
| self.assertEqual(len(test_exporter.gerrit.request_posted), 0) |
| |
| def test_creates_pull_request_for_all_exportable_commits(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub( |
| pull_requests=[], create_pr_fail_index=1) |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.get_exportable_commits = lambda: ([ |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#1}', change_id='I001', subject='subject 1', body='body 1'), |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#2}', change_id='I002', subject='subject 2', body='body 2'), |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#3}', change_id='I003', subject='subject 3', body='body 3'), |
| ], []) |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertTrue(success) |
| self.assertEqual( |
| test_exporter.wpt_github.calls, |
| [ |
| # 1 |
| 'pr_for_chromium_commit', |
| 'create_pr', |
| 'add_label "chromium-export"', |
| # 2 |
| 'pr_for_chromium_commit', |
| 'create_pr', |
| 'add_label "chromium-export"', |
| # 3 |
| 'pr_for_chromium_commit', |
| 'create_pr', |
| 'add_label "chromium-export"', |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, [ |
| ('chromium-export-96862edfc1', 'subject 1', |
| 'body 1\n\nChange-Id: I001\n'), |
| ('chromium-export-ce0e78bf18', 'subject 3', |
| 'body 3\n\nChange-Id: I003\n'), |
| ]) |
| |
| def test_creates_and_merges_pull_requests(self): |
| # This tests 4 exportable commits: |
| # 1. #458475 has a provisional in-flight PR associated with it. The PR needs to be updated but not merged. |
| # 2. #458476 has no PR associated with it and should have one created. |
| # 3. #458477 has a closed PR associated with it and should be skipped. |
| # 4. #458478 has an in-flight PR associated with it and should be merged successfully. |
| # 5. #458479 has an in-flight PR associated with it but can not be merged. |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub( |
| pull_requests=[ |
| PullRequest( |
| title='Open PR', |
| number=1234, |
| body= |
| 'rutabaga\nCr-Commit-Position: refs/heads/master@{#458475}\nChange-Id: I0005', |
| state='open', |
| labels=['do not merge yet']), |
| PullRequest( |
| title='Merged PR', |
| number=2345, |
| body= |
| 'rutabaga\nCr-Commit-Position: refs/heads/master@{#458477}\nChange-Id: Idead', |
| state='closed', |
| labels=[]), |
| PullRequest( |
| title='Open PR', |
| number=3456, |
| body= |
| 'rutabaga\nCr-Commit-Position: refs/heads/master@{#458478}\nChange-Id: I0118', |
| state='open', |
| labels=[] # It's important that this is empty. |
| ), |
| PullRequest( |
| title='Open PR', |
| number=4747, |
| body= |
| 'rutabaga\nCr-Commit-Position: refs/heads/master@{#458479}\nChange-Id: I0147', |
| state='open', |
| labels=[] # It's important that this is empty. |
| ), |
| ], |
| unsuccessful_merge_index=3) # Mark the last PR as unmergable. |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.get_exportable_commits = lambda: ([ |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#458475}', change_id='I0005'), |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#458476}', change_id='I0476'), |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#458477}', change_id='Idead'), |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#458478}', change_id='I0118'), |
| MockChromiumCommit( |
| self.host, position='refs/heads/master@{#458479}', change_id='I0147'), |
| ], []) |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertTrue(success) |
| self.assertEqual( |
| test_exporter.wpt_github.calls, |
| [ |
| # 1. #458475 |
| 'pr_for_chromium_commit', |
| 'get_pr_branch', |
| 'update_pr', |
| 'remove_label "do not merge yet"', |
| # 2. #458476 |
| 'pr_for_chromium_commit', |
| 'create_pr', |
| 'add_label "chromium-export"', |
| # 3. #458477 |
| 'pr_for_chromium_commit', |
| # 4. #458478 |
| 'pr_for_chromium_commit', |
| # Testing the lack of remove_label here. The exporter should not |
| # try to remove the provisional label from PRs it has already |
| # removed it from. |
| 'get_pr_branch', |
| 'merge_pr', |
| # 5. #458479 |
| 'pr_for_chromium_commit', |
| 'get_pr_branch', |
| 'merge_pr', |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, [ |
| ('chromium-export-52c3178508', 'Fake subject', |
| 'Fake body\n\nChange-Id: I0476\n'), |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_merged, [3456]) |
| |
| def test_new_gerrit_cl(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[]) |
| test_exporter.get_exportable_commits = lambda: ([], []) |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.gerrit.exportable_open_cls = [ |
| MockGerritCL( |
| data={ |
| 'change_id': 'I001', |
| 'subject': 'subject', |
| '_number': 1234, |
| 'current_revision': '1', |
| 'has_review_started': True, |
| 'revisions': { |
| '1': { |
| 'commit_with_footers': 'a commit with footers' |
| } |
| }, |
| 'owner': { |
| 'email': 'test@chromium.org' |
| }, |
| }, |
| api=test_exporter.gerrit, |
| chromium_commit=MockChromiumCommit( |
| self.host, |
| subject='subject', |
| body='fake body <html>', |
| change_id='I001')), |
| MockGerritCL( |
| data={ |
| 'change_id': 'I002', |
| 'subject': 'subject', |
| '_number': 1235, |
| 'current_revision': '1', |
| 'has_review_started': True, |
| 'revisions': { |
| '1': { |
| 'commit_with_footers': 'a commit with footers' |
| } |
| }, |
| 'owner': { |
| 'email': 'test@chromium.org' |
| }, |
| }, |
| api=test_exporter.gerrit, |
| chromium_commit=MockChromiumCommit( |
| self.host, subject='subject', body='body', |
| change_id=None)), |
| ] |
| test_exporter.main(['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertEqual(test_exporter.wpt_github.calls, [ |
| 'pr_with_change_id', |
| 'create_pr', |
| 'add_label "chromium-export"', |
| 'add_label "do not merge yet"', |
| 'pr_with_change_id', |
| 'create_pr', |
| 'add_label "chromium-export"', |
| 'add_label "do not merge yet"', |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, [ |
| ('chromium-export-cl-1234', 'subject', |
| 'fake body \\<html>\n\nChange-Id: I001\nReviewed-on: ' |
| 'https://chromium-review.googlesource.com/1234\n' |
| 'WPT-Export-Revision: 1'), |
| ('chromium-export-cl-1235', 'subject', |
| 'body\nChange-Id: I002\nReviewed-on: ' |
| 'https://chromium-review.googlesource.com/1235\n' |
| 'WPT-Export-Revision: 1'), |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_merged, []) |
| |
| def test_gerrit_cl_no_update_if_pr_with_same_revision(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[ |
| PullRequest( |
| title='title1', |
| number=1234, |
| body='description\nWPT-Export-Revision: 1', |
| state='open', |
| labels=[]), |
| ]) |
| test_exporter.get_exportable_commits = lambda: ([], []) |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.gerrit.exportable_open_cls = [ |
| MockGerritCL( |
| data={ |
| 'change_id': '1', |
| 'subject': 'subject', |
| '_number': 1, |
| 'current_revision': '1', |
| 'has_review_started': True, |
| 'revisions': { |
| '1': { |
| 'commit_with_footers': 'a commit with footers' |
| } |
| }, |
| 'owner': { |
| 'email': 'test@chromium.org' |
| }, |
| }, |
| api=test_exporter.gerrit, |
| chromium_commit=MockChromiumCommit(self.host)) |
| ] |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertTrue(success) |
| self.assertEqual(test_exporter.wpt_github.calls, [ |
| 'pr_with_change_id', |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, []) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_merged, []) |
| |
| def test_gerrit_cl_updates_if_cl_has_new_revision(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[ |
| PullRequest( |
| title='title1', |
| number=1234, |
| body='description\nWPT-Export-Revision: 1', |
| state='open', |
| labels=[]), |
| ]) |
| test_exporter.get_exportable_commits = lambda: ([], []) |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.gerrit.exportable_open_cls = [ |
| MockGerritCL( |
| data={ |
| 'change_id': '1', |
| 'subject': 'subject', |
| '_number': 1, |
| 'current_revision': '2', |
| 'has_review_started': True, |
| 'revisions': { |
| '1': { |
| 'commit_with_footers': 'a commit with footers 1', |
| 'description': 'subject 1', |
| }, |
| '2': { |
| 'commit_with_footers': 'a commit with footers 2', |
| 'description': 'subject 2', |
| }, |
| }, |
| 'owner': { |
| 'email': 'test@chromium.org' |
| }, |
| }, |
| api=test_exporter.gerrit, |
| chromium_commit=MockChromiumCommit(self.host)) |
| ] |
| test_exporter.main(['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertEqual(test_exporter.wpt_github.calls, [ |
| 'pr_with_change_id', |
| 'get_pr_branch', |
| 'update_pr', |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, []) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_merged, []) |
| |
| def test_attempts_to_merge_landed_gerrit_cl(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[ |
| PullRequest( |
| title='title1', |
| number=1234, |
| body='description\nWPT-Export-Revision: 9\nChange-Id: decafbad', |
| state='open', |
| labels=['do not merge yet']), |
| ]) |
| test_exporter.get_exportable_commits = lambda: ([ |
| MockChromiumCommit(self.host, change_id='decafbad'), ], []) |
| test_exporter.gerrit = MockGerritAPI() |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertTrue(success) |
| self.assertEqual(test_exporter.wpt_github.calls, [ |
| 'pr_for_chromium_commit', |
| 'get_pr_branch', |
| 'update_pr', |
| 'remove_label "do not merge yet"', |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, []) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_merged, []) |
| |
| def test_merges_non_provisional_pr(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[ |
| PullRequest( |
| title='title1', |
| number=1234, |
| body='description\nWPT-Export-Revision: 9\nChange-Id: decafbad', |
| state='open', |
| labels=['']), |
| ]) |
| test_exporter.get_exportable_commits = lambda: ([ |
| MockChromiumCommit(self.host, change_id='decafbad'), ], []) |
| test_exporter.gerrit = MockGerritAPI() |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertTrue(success) |
| self.assertEqual(test_exporter.wpt_github.calls, [ |
| 'pr_for_chromium_commit', |
| 'get_pr_branch', |
| 'merge_pr', |
| ]) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, []) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_merged, [1234]) |
| |
| def test_does_not_create_pr_if_cl_review_has_not_started(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[]) |
| test_exporter.get_exportable_commits = lambda: ([], []) |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.gerrit.exportable_open_cls = [ |
| MockGerritCL( |
| data={ |
| 'change_id': '1', |
| 'subject': 'subject', |
| '_number': 1, |
| 'current_revision': '2', |
| 'has_review_started': False, |
| 'revisions': { |
| '1': { |
| 'commit_with_footers': 'a commit with footers 1', |
| 'description': 'subject 1', |
| }, |
| '2': { |
| 'commit_with_footers': 'a commit with footers 2', |
| 'description': 'subject 2', |
| }, |
| }, |
| 'owner': { |
| 'email': 'test@chromium.org' |
| }, |
| }, |
| api=test_exporter.gerrit, |
| chromium_commit=MockChromiumCommit(self.host)) |
| ] |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertTrue(success) |
| self.assertEqual(test_exporter.wpt_github.calls, []) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_created, []) |
| self.assertEqual(test_exporter.wpt_github.pull_requests_merged, []) |
| |
| def test_run_returns_false_on_gerrit_search_error(self): |
| def raise_gerrit_error(): |
| raise GerritError('Gerrit API fails.') |
| |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[]) |
| test_exporter.get_exportable_commits = lambda: ([], []) |
| test_exporter.gerrit = MockGerritAPI() |
| test_exporter.gerrit.query_exportable_open_cls = raise_gerrit_error |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertFalse(success) |
| self.assertLog([ |
| 'INFO: Cloning GitHub web-platform-tests/wpt into /tmp/wpt\n', |
| 'INFO: Setting git user name & email in /tmp/wpt\n', |
| 'INFO: Searching for exportable in-flight CLs.\n', |
| 'INFO: In-flight CLs cannot be exported due to the following error:\n', |
| 'ERROR: Gerrit API fails.\n', |
| 'INFO: Searching for exportable Chromium commits.\n' |
| ]) |
| |
| def test_run_returns_false_on_patch_failure(self): |
| test_exporter = TestExporter(self.host) |
| test_exporter.wpt_github = MockWPTGitHub(pull_requests=[]) |
| test_exporter.get_exportable_commits = lambda: ( |
| [], ['There was an error with the rutabaga.']) |
| test_exporter.gerrit = MockGerritAPI() |
| success = test_exporter.main( |
| ['--credentials-json', '/tmp/credentials.json']) |
| |
| self.assertFalse(success) |
| self.assertLog([ |
| 'INFO: Cloning GitHub web-platform-tests/wpt into /tmp/wpt\n', |
| 'INFO: Setting git user name & email in /tmp/wpt\n', |
| 'INFO: Searching for exportable in-flight CLs.\n', |
| 'INFO: Searching for exportable Chromium commits.\n', |
| 'INFO: Attention: The following errors have prevented some commits from being exported:\n', |
| 'ERROR: There was an error with the rutabaga.\n' |
| ]) |