2010-06-10 Ojan Vafai <ojan@chromium.org>
[WebKit-https.git] / WebKitTools / Scripts / webkitpy / tool / commands / queues_unittest.py
1 # Copyright (C) 2009 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 #    * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #    * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #    * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 import os
30
31 from webkitpy.common.net.bugzilla import Attachment
32 from webkitpy.common.system.outputcapture import OutputCapture
33 from webkitpy.thirdparty.mock import Mock
34 from webkitpy.tool.commands.commandtest import CommandsTest
35 from webkitpy.tool.commands.queues import *
36 from webkitpy.tool.commands.queuestest import QueuesTest
37 from webkitpy.tool.mocktool import MockTool, MockSCM
38
39
40 class TestQueue(AbstractPatchQueue):
41     name = "test-queue"
42
43
44 class TestReviewQueue(AbstractReviewQueue):
45     name = "test-review-queue"
46
47
48 class MockPatch(object):
49     def is_rollout(self):
50         return True
51
52     def bug_id(self):
53         return 12345
54
55     def id(self):
56         return 76543
57
58
59 class AbstractQueueTest(CommandsTest):
60     def _assert_log_progress_output(self, patch_ids, progress_output):
61         OutputCapture().assert_outputs(self, TestQueue().log_progress, [patch_ids], expected_stderr=progress_output)
62
63     def test_log_progress(self):
64         self._assert_log_progress_output([1,2,3], "3 patches in test-queue [1, 2, 3]\n")
65         self._assert_log_progress_output(["1","2","3"], "3 patches in test-queue [1, 2, 3]\n")
66         self._assert_log_progress_output([1], "1 patch in test-queue [1]\n")
67
68     def test_log_directory(self):
69         self.assertEquals(TestQueue()._log_directory(), "test-queue-logs")
70
71     def _assert_run_webkit_patch(self, run_args):
72         queue = TestQueue()
73         tool = MockTool()
74         tool.executive = Mock()
75         queue.bind_to_tool(tool)
76
77         queue.run_webkit_patch(run_args)
78         expected_run_args = ["echo", "--status-host=example.com"] + run_args
79         tool.executive.run_and_throw_if_fail.assert_called_with(expected_run_args)
80
81     def test_run_webkit_patch(self):
82         self._assert_run_webkit_patch([1])
83         self._assert_run_webkit_patch(["one", 2])
84
85     def test_iteration_count(self):
86         queue = TestQueue()
87         queue.options = Mock()
88         queue.options.iterations = 3
89         self.assertTrue(queue.should_continue_work_queue())
90         self.assertTrue(queue.should_continue_work_queue())
91         self.assertTrue(queue.should_continue_work_queue())
92         self.assertFalse(queue.should_continue_work_queue())
93
94     def test_no_iteration_count(self):
95         queue = TestQueue()
96         queue.options = Mock()
97         self.assertTrue(queue.should_continue_work_queue())
98         self.assertTrue(queue.should_continue_work_queue())
99         self.assertTrue(queue.should_continue_work_queue())
100         self.assertTrue(queue.should_continue_work_queue())
101
102
103 class AbstractReviewQueueTest(CommandsTest):
104     def test_patch_collection_delegate_methods(self):
105         queue = TestReviewQueue()
106         tool = MockTool()
107         queue.bind_to_tool(tool)
108         self.assertEquals(queue.collection_name(), "test-review-queue")
109         self.assertEquals(queue.fetch_potential_patch_ids(), [103])
110         queue.status_server()
111         self.assertTrue(queue.is_terminal_status("Pass"))
112         self.assertTrue(queue.is_terminal_status("Fail"))
113         self.assertTrue(queue.is_terminal_status("Error: Your patch exploded"))
114         self.assertFalse(queue.is_terminal_status("Foo"))
115
116
117 class CommitQueueTest(QueuesTest):
118     def test_commit_queue(self):
119         expected_stderr = {
120             "begin_work_queue" : "CAUTION: commit-queue will discard all local changes in \"%s\"\nRunning WebKit commit-queue.\n" % MockSCM.fake_checkout_root,
121             "should_proceed_with_work_item": "MOCK: update_status: commit-queue Landing patch\n",
122             # FIXME: The commit-queue warns about bad committers twice.  This is due to the fact that we access Attachment.reviewer() twice and it logs each time.
123             "next_work_item" : """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
124 Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
125 MOCK setting flag 'commit-queue' to '-' on attachment '128' with comment 'Rejecting patch 128 from commit-queue.' and additional comment 'non-committer@example.com does not have committer permissions according to http://trac.webkit.org/browser/trunk/WebKitTools/Scripts/webkitpy/common/config/committers.py.\n\n- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.\n\n- If you have committer rights please correct the error in WebKitTools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed).  Due to bug 30084 the commit-queue will require a restart after your change.  Please contact eseidel@chromium.org to request a commit-queue restart.  After restart the commit-queue will correctly respect your committer rights.'
126 MOCK: update_work_items: commit-queue [106, 197]
127 2 patches in commit-queue [106, 197]
128 """,
129             "process_work_item" : "MOCK: update_status: commit-queue Pass\n",
130             "handle_unexpected_error" : "MOCK setting flag 'commit-queue' to '-' on attachment '1234' with comment 'Rejecting patch 1234 from commit-queue.' and additional comment 'Mock error message'\n",
131             "handle_script_error": "MOCK: update_status: commit-queue ScriptError error message\nMOCK setting flag 'commit-queue' to '-' on attachment '1234' with comment 'Rejecting patch 1234 from commit-queue.' and additional comment 'ScriptError error message'\n",
132         }
133         self.assert_queue_outputs(CommitQueue(), expected_stderr=expected_stderr)
134
135     def test_rollout(self):
136         tool = MockTool(log_executive=True)
137         tool.buildbot.light_tree_on_fire()
138         expected_stderr = {
139             "begin_work_queue" : "CAUTION: commit-queue will discard all local changes in \"%s\"\nRunning WebKit commit-queue.\n" % MockSCM.fake_checkout_root,
140             "should_proceed_with_work_item": "MOCK: update_status: commit-queue Builders [\"Builder2\"] are red. See http://build.webkit.org\n",
141             # FIXME: The commit-queue warns about bad committers twice.  This is due to the fact that we access Attachment.reviewer() twice and it logs each time.
142             "next_work_item" : """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
143 Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
144 MOCK setting flag \'commit-queue\' to \'-\' on attachment \'128\' with comment \'Rejecting patch 128 from commit-queue.\' and additional comment \'non-committer@example.com does not have committer permissions according to http://trac.webkit.org/browser/trunk/WebKitTools/Scripts/webkitpy/common/config/committers.py.\n\n- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.\n\n- If you have committer rights please correct the error in WebKitTools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed).  Due to bug 30084 the commit-queue will require a restart after your change.  Please contact eseidel@chromium.org to request a commit-queue restart.  After restart the commit-queue will correctly respect your committer rights.\'
145 MOCK: update_work_items: commit-queue [106, 197]
146 MOCK: update_status: commit-queue Builders ["Builder2"] are red. See http://build.webkit.org
147 1 patch in commit-queue [106]
148 """,
149             "process_work_item" : "MOCK: update_status: commit-queue Builders [\"Builder2\"] are red. See http://build.webkit.org\n",
150             "handle_unexpected_error" : "MOCK setting flag 'commit-queue' to '-' on attachment '1234' with comment 'Rejecting patch 1234 from commit-queue.' and additional comment 'Mock error message'\n",
151             "handle_script_error": "MOCK: update_status: commit-queue ScriptError error message\nMOCK setting flag 'commit-queue' to '-' on attachment '1234' with comment 'Rejecting patch 1234 from commit-queue.' and additional comment 'ScriptError error message'\n",
152         }
153         self.assert_queue_outputs(CommitQueue(), tool=tool, expected_stderr=expected_stderr)
154
155     def test_rollout_lands(self):
156         tool = MockTool(log_executive=True)
157         tool.buildbot.light_tree_on_fire()
158         rollout_patch = MockPatch()
159         expected_stderr = {
160             "begin_work_queue": "CAUTION: commit-queue will discard all local changes in \"%s\"\nRunning WebKit commit-queue.\n" % MockSCM.fake_checkout_root,
161             "should_proceed_with_work_item": "MOCK: update_status: commit-queue Landing rollout patch\n",
162             # FIXME: The commit-queue warns about bad committers twice.  This is due to the fact that we access Attachment.reviewer() twice and it logs each time.
163             "next_work_item": """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
164 Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
165 MOCK setting flag \'commit-queue\' to \'-\' on attachment \'128\' with comment \'Rejecting patch 128 from commit-queue.\' and additional comment \'non-committer@example.com does not have committer permissions according to http://trac.webkit.org/browser/trunk/WebKitTools/Scripts/webkitpy/common/config/committers.py.\n\n- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.\n\n- If you have committer rights please correct the error in WebKitTools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed).  Due to bug 30084 the commit-queue will require a restart after your change.  Please contact eseidel@chromium.org to request a commit-queue restart.  After restart the commit-queue will correctly respect your committer rights.\'
166 MOCK: update_work_items: commit-queue [106, 197]
167 MOCK: update_status: commit-queue Builders ["Builder2"] are red. See http://build.webkit.org
168 1 patch in commit-queue [106]
169 """,
170             "process_work_item": "MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'land-attachment', '--force-clean', '--build', '--non-interactive', '--ignore-builders', '--build-style=both', '--quiet', 76543]\nMOCK: update_status: commit-queue Pass\n",
171             "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '76543' with comment 'Rejecting patch 76543 from commit-queue.' and additional comment 'Mock error message'\n",
172             "handle_script_error": "MOCK: update_status: commit-queue ScriptError error message\nMOCK setting flag 'commit-queue' to '-' on attachment '1234' with comment 'Rejecting patch 1234 from commit-queue.' and additional comment 'ScriptError error message'\n",
173         }
174         self.assert_queue_outputs(CommitQueue(), tool=tool, work_item=rollout_patch, expected_stderr=expected_stderr)
175
176     def test_can_build_and_test(self):
177         queue = CommitQueue()
178         tool = MockTool()
179         tool.executive = Mock()
180         queue.bind_to_tool(tool)
181         self.assertTrue(queue._can_build_and_test())
182         expected_run_args = ["echo", "--status-host=example.com", "build-and-test", "--force-clean", "--build", "--test", "--non-interactive", "--no-update", "--build-style=both", "--quiet"]
183         tool.executive.run_and_throw_if_fail.assert_called_with(expected_run_args)
184
185     def _mock_attachment(self, is_rollout, attach_date):
186         attachment = Mock()
187         attachment.is_rollout = lambda: is_rollout
188         attachment.attach_date = lambda: attach_date
189         return attachment
190
191     def test_patch_cmp(self):
192         long_ago_date = datetime(1900, 1, 21)
193         recent_date = datetime(2010, 1, 21)
194         attachment1 = self._mock_attachment(is_rollout=False, attach_date=recent_date)
195         attachment2 = self._mock_attachment(is_rollout=False, attach_date=long_ago_date)
196         attachment3 = self._mock_attachment(is_rollout=True, attach_date=recent_date)
197         attachment4 = self._mock_attachment(is_rollout=True, attach_date=long_ago_date)
198         attachments = [attachment1, attachment2, attachment3, attachment4]
199         expected_sort = [attachment4, attachment3, attachment2, attachment1]
200         queue = CommitQueue()
201         attachments.sort(queue._patch_cmp)
202         self.assertEqual(attachments, expected_sort)
203
204
205 class RietveldUploadQueueTest(QueuesTest):
206     def test_rietveld_upload_queue(self):
207         expected_stderr = {
208             "begin_work_queue": "CAUTION: rietveld-upload-queue will discard all local changes in \"%s\"\nRunning WebKit rietveld-upload-queue.\n" % MockSCM.fake_checkout_root,
209             "should_proceed_with_work_item": "MOCK: update_status: rietveld-upload-queue Uploading patch\n",
210             "process_work_item": "MOCK: update_status: rietveld-upload-queue Pass\n",
211             "handle_unexpected_error": "Mock error message\nMOCK setting flag 'in-rietveld' to '-' on attachment '1234' with comment 'None' and additional comment 'None'\n",
212             "handle_script_error": "ScriptError error message\nMOCK: update_status: rietveld-upload-queue ScriptError error message\nMOCK setting flag 'in-rietveld' to '-' on attachment '1234' with comment 'None' and additional comment 'None'\n",
213         }
214         self.assert_queue_outputs(RietveldUploadQueue(), expected_stderr=expected_stderr)
215
216
217 class StyleQueueTest(QueuesTest):
218     def test_style_queue(self):
219         expected_stderr = {
220             "begin_work_queue" : "CAUTION: style-queue will discard all local changes in \"%s\"\nRunning WebKit style-queue.\n" % MockSCM.fake_checkout_root,
221             "next_work_item": "MOCK: update_work_items: style-queue [103]\n",
222             "should_proceed_with_work_item": "MOCK: update_status: style-queue Checking style\n",
223             "process_work_item" : "MOCK: update_status: style-queue Pass\n",
224             "handle_unexpected_error" : "Mock error message\n",
225             "handle_script_error": "MOCK: update_status: style-queue ScriptError error message\nMOCK bug comment: bug_id=345, cc=[]\n--- Begin comment ---\\Attachment 1234 did not pass style-queue:\n\nScriptError error message\n\nIf any of these errors are false positives, please file a bug against check-webkit-style.\n--- End comment ---\n\n",
226         }
227         expected_exceptions = {
228             "handle_script_error": SystemExit,
229         }
230         self.assert_queue_outputs(StyleQueue(), expected_stderr=expected_stderr, expected_exceptions=expected_exceptions)