summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJames E. Blair <jim@acmegating.com>2022-03-05 11:16:15 -0800
committerJames E. Blair <jim@acmegating.com>2022-03-21 12:53:55 -0700
commit81d84e7c15d46a7e4b3557824552b941e4c60182 (patch)
treed0eb4b8ee9ebd51be8faf25fca5f8f4849ae8676 /tests
parentd05035f6cd0e37bab8c03f8791e538934d94ee5d (diff)
downloadzuul-81d84e7c15d46a7e4b3557824552b941e4c60182.tar.gz
Support submitWholeTopic in Gerrit
This adds a query for changes which are set (by Gerrit) to be submitted together due to submitWholeTopic being enabled. In this case, changes which are of the same topic will be merged simultaneously by Gerrit, therefore Zuul should treat them as a set of circular dependencies. The behavior is automatic, since Gerrit will return a set of changes if the setting is enabled, or the empty list if it is not. Zuul still requires that circular dependencies be enabled in any queues where they appear. If users have submitWholeTopic enabled in Gerrit but do not have allow-circular-dependencies enabled, they may begin to see errors. However, the errors are self-explanatory, and installations such as these are already not testing what Gerrit will merge, so reporting the discrepancy is an improvement. Change-Id: Icf65913a049a9b9ddbedd20cc73bf44ffcc831b8
Diffstat (limited to 'tests')
-rw-r--r--tests/base.py34
-rw-r--r--tests/fixtures/zuul-gerrit-github.conf1
-rw-r--r--tests/unit/test_circular_dependencies.py39
-rw-r--r--tests/unit/test_web.py4
4 files changed, 74 insertions, 4 deletions
diff --git a/tests/base.py b/tests/base.py
index 262e2d595..7778ba763 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -383,7 +383,8 @@ class FakeGerritChange(object):
def __init__(self, gerrit, number, project, branch, subject,
status='NEW', upstream_root=None, files={},
- parent=None, merge_parents=None, merge_files=None):
+ parent=None, merge_parents=None, merge_files=None,
+ topic=None):
self.gerrit = gerrit
self.source = gerrit
self.reported = 0
@@ -421,6 +422,8 @@ class FakeGerritChange(object):
'submitRecords': [],
'url': '%s/%s' % (self.gerrit.baseurl.rstrip('/'), number)}
+ if topic:
+ self.data['topic'] = topic
self.upstream_root = upstream_root
if merge_parents:
self.addMergePatchset(parents=merge_parents,
@@ -957,6 +960,7 @@ class GerritWebServer(object):
class Server(http.server.SimpleHTTPRequestHandler):
log = logging.getLogger("zuul.test.FakeGerritConnection")
review_re = re.compile('/a/changes/(.*?)/revisions/(.*?)/review')
+ together_re = re.compile('/a/changes/(.*?)/submitted_together')
submit_re = re.compile('/a/changes/(.*?)/submit')
pending_checks_re = re.compile(
r'/a/plugins/checks/checks\.pending/\?'
@@ -1005,6 +1009,9 @@ class GerritWebServer(object):
m = self.files_re.match(path)
if m:
return self.get_files(m.group(1), m.group(2))
+ m = self.together_re.match(path)
+ if m:
+ return self.get_submitted_together(m.group(1))
m = self.change_search_re.match(path)
if m:
return self.get_changes(m.group(1))
@@ -1132,6 +1139,21 @@ class GerritWebServer(object):
self.send_data(data)
self.end_headers()
+ def get_submitted_together(self, number):
+ change = fake_gerrit.changes.get(int(number))
+ if not change:
+ return self._404()
+ topic = change.data.get('topic')
+ if not fake_gerrit._fake_submit_whole_topic:
+ topic = None
+ if topic:
+ results = fake_gerrit._simpleQuery(
+ f'topic:{topic}', http=True)
+ else:
+ results = []
+ self.send_data(results)
+ self.end_headers()
+
def get_changes(self, query):
self.log.debug("simpleQueryHTTP: %s", query)
query = urllib.parse.unquote(query)
@@ -1262,6 +1284,7 @@ class FakeGerritConnection(gerritconnection.GerritConnection):
self.fake_checkers = []
self._poller_event = poller_event
self._ref_watcher_event = ref_watcher_event
+ self._fake_submit_whole_topic = False
def onStop(self):
super().onStop()
@@ -1273,14 +1296,15 @@ class FakeGerritConnection(gerritconnection.GerritConnection):
def addFakeChange(self, project, branch, subject, status='NEW',
files=None, parent=None, merge_parents=None,
- merge_files=None):
+ merge_files=None, topic=None):
"""Add a change to the fake Gerrit."""
self.change_number += 1
c = FakeGerritChange(self, self.change_number, project, branch,
subject, upstream_root=self.upstream_root,
status=status, files=files, parent=parent,
merge_parents=merge_parents,
- merge_files=merge_files)
+ merge_files=merge_files,
+ topic=topic)
self.changes[self.change_number] = c
return c
@@ -1431,6 +1455,10 @@ class FakeGerritConnection(gerritconnection.GerritConnection):
queryMethod(change) for change in self.changes.values()
if change.data["lastUpdated"] >= cut_off_time
]
+ elif query.startswith('topic:'):
+ topic = query[len('topic:'):].strip()
+ l = [queryMethod(change) for change in self.changes.values()
+ if topic in change.data.get('topic', '')]
else:
# Query all open changes
l = [queryMethod(change) for change in self.changes.values()]
diff --git a/tests/fixtures/zuul-gerrit-github.conf b/tests/fixtures/zuul-gerrit-github.conf
index 1b2813dd4..0d03bacc2 100644
--- a/tests/fixtures/zuul-gerrit-github.conf
+++ b/tests/fixtures/zuul-gerrit-github.conf
@@ -20,6 +20,7 @@ driver=gerrit
server=review.example.com
user=jenkins
sshkey=fake_id_rsa_path
+password=badpassword
[connection github]
driver=github
diff --git a/tests/unit/test_circular_dependencies.py b/tests/unit/test_circular_dependencies.py
index 0b48a66a9..713408ee9 100644
--- a/tests/unit/test_circular_dependencies.py
+++ b/tests/unit/test_circular_dependencies.py
@@ -1410,6 +1410,45 @@ class TestGerritCircularDependencies(ZuulTestCase):
self.assertEqual(B.data['status'], 'NEW')
self.assertEqual(C.data['status'], 'MERGED')
+ def test_submitted_together(self):
+ self.fake_gerrit._fake_submit_whole_topic = True
+ A = self.fake_gerrit.addFakeChange('org/project1', "master", "A",
+ topic='test-topic')
+ B = self.fake_gerrit.addFakeChange('org/project2', "master", "B",
+ topic='test-topic')
+
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ self.assertEqual(len(A.patchsets[-1]["approvals"]), 1)
+ self.assertEqual(A.patchsets[-1]["approvals"][0]["type"], "Verified")
+ self.assertEqual(A.patchsets[-1]["approvals"][0]["value"], "1")
+
+ self.assertEqual(len(B.patchsets[-1]["approvals"]), 1)
+ self.assertEqual(B.patchsets[-1]["approvals"][0]["type"], "Verified")
+ self.assertEqual(B.patchsets[-1]["approvals"][0]["value"], "1")
+
+ # We're about to add approvals to changes without adding the
+ # triggering events to Zuul, so that we can be sure that it is
+ # enqueing the changes based on dependencies, not because of
+ # triggering events. Since it will have the changes cached
+ # already (without approvals), we need to clear the cache
+ # first.
+ for connection in self.scheds.first.connections.connections.values():
+ connection.maintainCache([], max_age=0)
+
+ A.addApproval("Code-Review", 2)
+ B.addApproval("Code-Review", 2)
+ A.addApproval("Approved", 1)
+ self.fake_gerrit.addEvent(B.addApproval("Approved", 1))
+ self.waitUntilSettled()
+
+ self.assertEqual(A.reported, 3)
+ self.assertEqual(B.reported, 3)
+ self.assertEqual(A.data["status"], "MERGED")
+ self.assertEqual(B.data["status"], "MERGED")
+
class TestGithubCircularDependencies(ZuulTestCase):
config_file = "zuul-gerrit-github.conf"
diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py
index 9be7efd2b..87570e270 100644
--- a/tests/unit/test_web.py
+++ b/tests/unit/test_web.py
@@ -2665,10 +2665,12 @@ class TestWebMulti(BaseTestWeb):
def test_web_connections_list_multi(self):
data = self.get_url('api/connections').json()
+ port = self.web.connections.connections['gerrit'].web_server.port
+ url = f'http://localhost:{port}'
gerrit_connection = {
'driver': 'gerrit',
'name': 'gerrit',
- 'baseurl': 'https://review.example.com',
+ 'baseurl': url,
'canonical_hostname': 'review.example.com',
'server': 'review.example.com',
'port': 29418,