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
29import unittest
30
31from webkitpy.common.system.outputcapture import OutputCapture
32from webkitpy.thirdparty.mock import Mock
33from webkitpy.tool.commands.commandtest import CommandsTest
34from webkitpy.tool.commands.download import *
35from webkitpy.tool.mocktool import MockCheckout, MockOptions, MockTool
36
37
38class AbstractRolloutPrepCommandTest(unittest.TestCase):
39    def test_commit_info(self):
40        command = AbstractRolloutPrepCommand()
41        tool = MockTool()
42        command.bind_to_tool(tool)
43        output = OutputCapture()
44
45        expected_stderr = "Preparing rollout for bug 42.\n"
46        commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_stderr=expected_stderr)
47        self.assertTrue(commit_info)
48
49        mock_commit_info = Mock()
50        mock_commit_info.bug_id = lambda: None
51        tool._checkout.commit_info_for_revision = lambda revision: mock_commit_info
52        expected_stderr = "Unable to parse bug number from diff.\n"
53        commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_stderr=expected_stderr)
54        self.assertEqual(commit_info, mock_commit_info)
55
56    def test_prepare_state(self):
57        command = AbstractRolloutPrepCommand()
58        mock_commit_info = MockCheckout().commit_info_for_revision(123)
59        command._commit_info = lambda revision: mock_commit_info
60
61        state = command._prepare_state(None, ["124 123 125", "Reason"], None)
62        self.assertEqual(123, state["revision"])
63        self.assertEqual([123, 124, 125], state["revision_list"])
64
65        self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 r122  123", "Reason"], tool=None)
66        self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 foo 123", "Reason"], tool=None)
67
68
69class DownloadCommandsTest(CommandsTest):
70    def _default_options(self):
71        options = MockOptions()
72        options.build = True
73        options.build_style = True
74        options.check_builders = True
75        options.check_style = True
76        options.clean = True
77        options.close_bug = True
78        options.force_clean = False
79        options.force_patch = True
80        options.non_interactive = False
81        options.parent_command = 'MOCK parent command'
82        options.quiet = False
83        options.test = True
84        options.update = True
85        return options
86
87    def test_build(self):
88        expected_stderr = "Updating working directory\nBuilding WebKit\n"
89        self.assert_execute_outputs(Build(), [], options=self._default_options(), expected_stderr=expected_stderr)
90
91    def test_build_and_test(self):
92        expected_stderr = "Updating working directory\nBuilding WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\n"
93        self.assert_execute_outputs(BuildAndTest(), [], options=self._default_options(), expected_stderr=expected_stderr)
94
95    def test_apply_attachment(self):
96        options = self._default_options()
97        options.update = True
98        options.local_commit = True
99        expected_stderr = "Updating working directory\nProcessing 1 patch from 1 bug.\nProcessing patch 197 from bug 42.\n"
100        self.assert_execute_outputs(ApplyAttachment(), [197], options=options, expected_stderr=expected_stderr)
101
102    def test_apply_patches(self):
103        options = self._default_options()
104        options.update = True
105        options.local_commit = True
106        expected_stderr = "Updating working directory\n2 reviewed patches found on bug 42.\nProcessing 2 patches from 1 bug.\nProcessing patch 197 from bug 42.\nProcessing patch 128 from bug 42.\n"
107        self.assert_execute_outputs(ApplyFromBug(), [42], options=options, expected_stderr=expected_stderr)
108
109    def test_land_diff(self):
110        expected_stderr = "Building WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\nUpdating bug 42\n"
111        mock_tool = MockTool()
112        mock_tool.scm().create_patch = Mock(return_value="Patch1\nMockPatch\n")
113        mock_tool.checkout().modified_changelogs = Mock(return_value=[])
114        self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr, tool=mock_tool)
115        # Make sure we're not calling expensive calls too often.
116        self.assertEqual(mock_tool.scm().create_patch.call_count, 1)
117        self.assertEqual(mock_tool.checkout().modified_changelogs.call_count, 1)
118
119    def test_land_red_builders(self):
120        expected_stderr = '\nWARNING: Builders ["Builder2"] are red, please watch your commit carefully.\nSee http://dummy_buildbot_host/console?category=core\n\nBuilding WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\nUpdating bug 42\n'
121        mock_tool = MockTool()
122        mock_tool.buildbot.light_tree_on_fire()
123        self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr, tool=mock_tool)
124
125    def test_check_style(self):
126        expected_stderr = """Processing 1 patch from 1 bug.
127Updating working directory
128MOCK run_and_throw_if_fail: ['mock-update-webkit']
129Processing patch 197 from bug 42.
130MOCK run_and_throw_if_fail: ['mock-check-webkit-style', '--git-commit', 'MOCK git commit', '--diff-files', 'MockFile1']
131"""
132        self.assert_execute_outputs(CheckStyle(), [197], options=self._default_options(), expected_stderr=expected_stderr, tool=MockTool(log_executive=True))
133
134    def test_build_attachment(self):
135        expected_stderr = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 197 from bug 42.\nBuilding WebKit\n"
136        self.assert_execute_outputs(BuildAttachment(), [197], options=self._default_options(), expected_stderr=expected_stderr)
137
138    def test_land_attachment(self):
139        # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
140        expected_stderr = """Processing 1 patch from 1 bug.
141Updating working directory
142Processing patch 197 from bug 42.
143Building WebKit
144Running Python unit tests
145Running Perl unit tests
146Running JavaScriptCore tests
147Running run-webkit-tests
148Committed r49824: <http://trac.webkit.org/changeset/49824>
149Not closing bug 42 as attachment 197 has review=+.  Assuming there are more patches to land from this bug.
150"""
151        self.assert_execute_outputs(LandAttachment(), [197], options=self._default_options(), expected_stderr=expected_stderr)
152
153    def test_land_patches(self):
154        # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
155        expected_stderr = """2 reviewed patches found on bug 42.
156Processing 2 patches from 1 bug.
157Updating working directory
158Processing patch 197 from bug 42.
159Building WebKit
160Running Python unit tests
161Running Perl unit tests
162Running JavaScriptCore tests
163Running run-webkit-tests
164Committed r49824: <http://trac.webkit.org/changeset/49824>
165Not closing bug 42 as attachment 197 has review=+.  Assuming there are more patches to land from this bug.
166Updating working directory
167Processing patch 128 from bug 42.
168Building WebKit
169Running Python unit tests
170Running Perl unit tests
171Running JavaScriptCore tests
172Running run-webkit-tests
173Committed r49824: <http://trac.webkit.org/changeset/49824>
174Not closing bug 42 as attachment 197 has review=+.  Assuming there are more patches to land from this bug.
175"""
176        self.assert_execute_outputs(LandFromBug(), [42], options=self._default_options(), expected_stderr=expected_stderr)
177
178    def test_prepare_rollout(self):
179        expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\n"
180        self.assert_execute_outputs(PrepareRollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
181
182    def test_create_rollout(self):
183        expected_stderr = """Preparing rollout for bug 42.
184Updating working directory
185MOCK create_bug
186bug_title: REGRESSION(r852): Reason
187bug_description: http://trac.webkit.org/changeset/852 broke the build:
188Reason
189component: MOCK component
190cc: MOCK cc
191blocked: 42
192MOCK add_patch_to_bug: bug_id=78, description=ROLLOUT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
193-- Begin comment --
194Any committer can land this patch automatically by marking it commit-queue+.  The commit-queue will build and test the patch before landing to ensure that the rollout will be successful.  This process takes approximately 15 minutes.
195
196If you would like to land the rollout faster, you can use the following command:
197
198  webkit-patch land-attachment ATTACHMENT_ID --ignore-builders
199
200where ATTACHMENT_ID is the ID of this attachment.
201-- End comment --
202"""
203        self.assert_execute_outputs(CreateRollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
204        self.assert_execute_outputs(CreateRollout(), ["855 852 854", "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
205
206    def test_rollout(self):
207        expected_stderr = """Preparing rollout for bug 42.
208Updating working directory
209MOCK: user.open_url: file://...
210Was that diff correct?
211Building WebKit
212Committed r49824: <http://trac.webkit.org/changeset/49824>
213"""
214        self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
215
216