diff options
author | James E. Blair <jim@acmegating.com> | 2022-03-05 11:16:15 -0800 |
---|---|---|
committer | James E. Blair <jim@acmegating.com> | 2022-03-21 12:53:55 -0700 |
commit | 81d84e7c15d46a7e4b3557824552b941e4c60182 (patch) | |
tree | d0eb4b8ee9ebd51be8faf25fca5f8f4849ae8676 /tests | |
parent | d05035f6cd0e37bab8c03f8791e538934d94ee5d (diff) | |
download | zuul-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.py | 34 | ||||
-rw-r--r-- | tests/fixtures/zuul-gerrit-github.conf | 1 | ||||
-rw-r--r-- | tests/unit/test_circular_dependencies.py | 39 | ||||
-rw-r--r-- | tests/unit/test_web.py | 4 |
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, |