summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/mock_bugzillatool.py
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/mock_bugzillatool.py')
-rw-r--r--WebKitTools/Scripts/webkitpy/mock_bugzillatool.py367
1 files changed, 367 insertions, 0 deletions
diff --git a/WebKitTools/Scripts/webkitpy/mock_bugzillatool.py b/WebKitTools/Scripts/webkitpy/mock_bugzillatool.py
new file mode 100644
index 0000000..1aff53a
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/mock_bugzillatool.py
@@ -0,0 +1,367 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+
+from webkitpy.bugzilla import Bug, Attachment
+from webkitpy.committers import CommitterList, Reviewer
+from webkitpy.mock import Mock
+from webkitpy.scm import CommitMessage
+from webkitpy.webkit_logging import log
+
+
+def _id_to_object_dictionary(*objects):
+ dictionary = {}
+ for thing in objects:
+ dictionary[thing["id"]] = thing
+ return dictionary
+
+
+# FIXME: The ids should be 1, 2, 3 instead of crazy numbers.
+
+
+_patch1 = {
+ "id": 197,
+ "bug_id": 42,
+ "url": "http://example.com/197",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "commit-queue": "+",
+ "committer_email": "foo@bar.com",
+ "attacher_email": "Contributer1",
+}
+
+
+_patch2 = {
+ "id": 128,
+ "bug_id": 42,
+ "url": "http://example.com/128",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "commit-queue": "+",
+ "committer_email": "non-committer@example.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch3 = {
+ "id": 103,
+ "bug_id": 75,
+ "url": "http://example.com/103",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "?",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch4 = {
+ "id": 104,
+ "bug_id": 77,
+ "url": "http://example.com/103",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "commit-queue": "?",
+ "reviewer_email": "foo@bar.com",
+ "attacher_email": "Contributer2",
+}
+
+
+_patch5 = {
+ "id": 105,
+ "bug_id": 77,
+ "url": "http://example.com/103",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch6 = { # Valid committer, but no reviewer.
+ "id": 106,
+ "bug_id": 77,
+ "url": "http://example.com/103",
+ "is_obsolete": False,
+ "is_patch": True,
+ "commit-queue": "+",
+ "committer_email": "foo@bar.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch7 = { # Valid review, patch is marked obsolete.
+ "id": 107,
+ "bug_id": 76,
+ "url": "http://example.com/103",
+ "is_obsolete": True,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+# This must be defined before we define the bugs, thus we don't use
+# MockBugzilla.unassigned_email directly.
+_unassigned_email = "unassigned@example.com"
+
+
+# FIXME: The ids should be 1, 2, 3 instead of crazy numbers.
+
+
+_bug1 = {
+ "id": 42,
+ "title": "Bug with two r+'d and cq+'d patches, one of which has an "
+ "invalid commit-queue setter.",
+ "assigned_to_email": _unassigned_email,
+ "attachments": [_patch1, _patch2],
+}
+
+
+_bug2 = {
+ "id": 75,
+ "title": "Bug with a patch needing review.",
+ "assigned_to_email": "foo@foo.com",
+ "attachments": [_patch3],
+}
+
+
+_bug3 = {
+ "id": 76,
+ "title": "The third bug",
+ "assigned_to_email": _unassigned_email,
+ "attachments": [_patch7],
+}
+
+
+_bug4 = {
+ "id": 77,
+ "title": "The fourth bug",
+ "assigned_to_email": "foo@foo.com",
+ "attachments": [_patch4, _patch5, _patch6],
+}
+
+
+class MockBugzillaQueries(Mock):
+
+ def __init__(self, bugzilla):
+ Mock.__init__(self)
+ self._bugzilla = bugzilla
+
+ def _all_bugs(self):
+ return map(lambda bug_dictionary: Bug(bug_dictionary, self._bugzilla),
+ self._bugzilla.bug_cache.values())
+
+ def fetch_bug_ids_from_commit_queue(self):
+ bugs_with_commit_queued_patches = filter(
+ lambda bug: bug.commit_queued_patches(),
+ self._all_bugs())
+ return map(lambda bug: bug.id(), bugs_with_commit_queued_patches)
+
+ def fetch_attachment_ids_from_review_queue(self):
+ unreviewed_patches = sum([bug.unreviewed_patches()
+ for bug in self._all_bugs()], [])
+ return map(lambda patch: patch.id(), unreviewed_patches)
+
+ def fetch_patches_from_commit_queue(self):
+ return sum([bug.commit_queued_patches()
+ for bug in self._all_bugs()], [])
+
+ def fetch_bug_ids_from_pending_commit_list(self):
+ bugs_with_reviewed_patches = filter(lambda bug: bug.reviewed_patches(),
+ self._all_bugs())
+ bug_ids = map(lambda bug: bug.id(), bugs_with_reviewed_patches)
+ # NOTE: This manual hack here is to allow testing logging in
+ # test_assign_to_committer the real pending-commit query on bugzilla
+ # will return bugs with patches which have r+, but are also obsolete.
+ return bug_ids + [76]
+
+ def fetch_patches_from_pending_commit_list(self):
+ return sum([bug.reviewed_patches() for bug in self._all_bugs()], [])
+
+
+# FIXME: Bugzilla is the wrong Mock-point. Once we have a BugzillaNetwork
+# class we should mock that instead.
+# Most of this class is just copy/paste from Bugzilla.
+
+
+class MockBugzilla(Mock):
+
+ bug_server_url = "http://example.com"
+
+ unassigned_email = _unassigned_email
+
+ bug_cache = _id_to_object_dictionary(_bug1, _bug2, _bug3, _bug4)
+
+ attachment_cache = _id_to_object_dictionary(_patch1,
+ _patch2,
+ _patch3,
+ _patch4,
+ _patch5,
+ _patch6,
+ _patch7)
+
+ def __init__(self):
+ Mock.__init__(self)
+ self.queries = MockBugzillaQueries(self)
+ self.committers = CommitterList(reviewers=[Reviewer("Foo Bar",
+ "foo@bar.com")])
+
+ def fetch_bug(self, bug_id):
+ return Bug(self.bug_cache.get(bug_id), self)
+
+ def fetch_attachment(self, attachment_id):
+ # This could be changed to .get() if we wish to allow failed lookups.
+ attachment_dictionary = self.attachment_cache[attachment_id]
+ bug = self.fetch_bug(attachment_dictionary["bug_id"])
+ for attachment in bug.attachments(include_obsolete=True):
+ if attachment.id() == int(attachment_id):
+ return attachment
+
+ def bug_url_for_bug_id(self, bug_id):
+ return "%s/%s" % (self.bug_server_url, bug_id)
+
+ def fetch_bug_dictionary(self, bug_id):
+ return self.bug_cache.get(bug_id)
+
+ def attachment_url_for_id(self, attachment_id, action="view"):
+ action_param = ""
+ if action and action != "view":
+ action_param = "&action=%s" % action
+ return "%s/%s%s" % (self.bug_server_url, attachment_id, action_param)
+
+
+class MockBuildBot(Mock):
+
+ def builder_statuses(self):
+ return [{
+ "name": "Builder1",
+ "is_green": True,
+ }, {
+ "name": "Builder2",
+ "is_green": True,
+ }]
+
+ def red_core_builders_names(self):
+ return []
+
+
+class MockSCM(Mock):
+
+ def __init__(self):
+ Mock.__init__(self)
+ self.checkout_root = os.getcwd()
+
+ def create_patch(self):
+ return "Patch1"
+
+ def commit_ids_from_commitish_arguments(self, args):
+ return ["Commitish1", "Commitish2"]
+
+ def commit_message_for_local_commit(self, commit_id):
+ if commit_id == "Commitish1":
+ return CommitMessage("CommitMessage1\n" \
+ "https://bugs.example.org/show_bug.cgi?id=42\n")
+ if commit_id == "Commitish2":
+ return CommitMessage("CommitMessage2\n" \
+ "https://bugs.example.org/show_bug.cgi?id=75\n")
+ raise Exception("Bogus commit_id in commit_message_for_local_commit.")
+
+ def create_patch_from_local_commit(self, commit_id):
+ if commit_id == "Commitish1":
+ return "Patch1"
+ if commit_id == "Commitish2":
+ return "Patch2"
+ raise Exception("Bogus commit_id in commit_message_for_local_commit.")
+
+ def diff_for_revision(self, revision):
+ return "DiffForRevision%s\n" \
+ "http://bugs.webkit.org/show_bug.cgi?id=12345" % revision
+
+ def svn_revision_from_commit_text(self, commit_text):
+ return "49824"
+
+ def modified_changelogs(self):
+ # Ideally we'd return something more interesting here. The problem is
+ # that LandDiff will try to actually read the path from disk!
+ return []
+
+
+class MockUser(object):
+
+ def prompt(self, message):
+ return "Mock user response"
+
+ def edit(self, files):
+ pass
+
+ def page(self, message):
+ pass
+
+ def confirm(self, message=None):
+ return True
+
+ def open_url(self, url):
+ log("MOCK: user.open_url: %s" % url)
+ pass
+
+
+class MockStatusServer(object):
+
+ def __init__(self):
+ self.host = "example.com"
+
+ def patch_status(self, queue_name, patch_id):
+ return None
+
+ def update_status(self, queue_name, status, patch=None, results_file=None):
+ return 187
+
+
+class MockBugzillaTool():
+
+ def __init__(self):
+ self.bugs = MockBugzilla()
+ self.buildbot = MockBuildBot()
+ self.executive = Mock()
+ self.user = MockUser()
+ self._scm = MockSCM()
+ self.status_server = MockStatusServer()
+
+ def scm(self):
+ return self._scm
+
+ def path(self):
+ return "echo"