summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJames E. Blair <jim@acmegating.com>2022-03-09 14:28:24 -0800
committerJames E. Blair <jim@acmegating.com>2022-03-10 14:09:32 -0800
commitbc1618ed5b683b7c43072e2c26c6a19d6dc8d9f5 (patch)
treefac0d2637835ce3c84796ca55faeb4e49a9d2460 /tests
parentc41139d904ab011a22ec67aee145d15e3fa54238 (diff)
downloadzuul-bc1618ed5b683b7c43072e2c26c6a19d6dc8d9f5.tar.gz
Make promote work for any pipeline manager
This alters the behavior of the promote event handler so that it does something useful in independent pipelines as well as dependent. It not only re-orders changes within a pipeline's shared queue (the old behavior), but it also re-orders the shared queue within the pipeline. When used in an independent pipeline, this will give the item an advantage when requesting nodes or semaphores, or starting jobs. This behavior applies to dependent pipelines as well -- the behavior is the same for every pipeline. Restarting jobs for changes in independent pipelines would be counter-productive (and even in dependent pipelines we may have restarted more jobs than necessary if the change at the head wasn't being altered), so it has been altered to only dequeue/enqueue items when necessary to achieve the requested order. The event argument to addChange within the promote method has been changed from the promote event to the original item enqueue event. Methods within the pipeline manager assume that event type is a TriggerEvent rather than a ManagementEvent and could throw some (non-fatal) errors when reporting. Change-Id: Ib4ab855cff27bf8e96aa852333fb4ace656235b4
Diffstat (limited to 'tests')
-rw-r--r--tests/unit/test_web.py166
1 files changed, 166 insertions, 0 deletions
diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py
index 9be7efd2b..f29c615b6 100644
--- a/tests/unit/test_web.py
+++ b/tests/unit/test_web.py
@@ -2205,6 +2205,172 @@ class TestTenantScopedWebApi(BaseTestWeb):
self.assertEqual(B.reported, 2)
self.assertEqual(C.data['status'], 'MERGED')
self.assertEqual(C.reported, 2)
+ self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
+ self.assertEqual(len(self.history), 10)
+
+ def test_promote_no_change(self):
+ """Test that jobs are not unecessarily restarted when promoting"""
+ self.executor_server.hold_jobs_in_build = True
+ A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+ B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
+ C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
+ A.addApproval('Code-Review', 2)
+ B.addApproval('Code-Review', 2)
+ C.addApproval('Code-Review', 2)
+
+ self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
+ self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
+ self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
+
+ self.waitUntilSettled()
+
+ tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
+ items = tenant.layout.pipelines['gate'].getAllItems()
+ enqueue_times = {}
+ for item in items:
+ enqueue_times[str(item.change)] = item.enqueue_time
+
+ # REST API
+ args = {'pipeline': 'gate',
+ 'changes': ['1,1', '2,1', '3,1']}
+ authz = {'iss': 'zuul_operator',
+ 'aud': 'zuul.example.com',
+ 'sub': 'testuser',
+ 'zuul': {
+ 'admin': ['tenant-one', ],
+ },
+ 'exp': time.time() + 3600,
+ 'iat': time.time()}
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
+ algorithm='HS256')
+ req = self.post_url(
+ 'api/tenant/tenant-one/promote',
+ headers={'Authorization': 'Bearer %s' % token},
+ json=args)
+ self.assertEqual(200, req.status_code, req.text)
+ data = req.json()
+ self.assertEqual(True, data)
+
+ # ensure that enqueue times are durable
+ items = tenant.layout.pipelines['gate'].getAllItems()
+ for item in items:
+ self.assertEqual(
+ enqueue_times[str(item.change)], item.enqueue_time)
+
+ self.waitUntilSettled()
+ self.executor_server.release('.*-merge')
+ self.waitUntilSettled()
+ self.executor_server.release('.*-merge')
+ self.waitUntilSettled()
+ self.executor_server.release('.*-merge')
+ self.waitUntilSettled()
+
+ self.assertEqual(len(self.builds), 6)
+ self.assertEqual(self.builds[0].name, 'project-test1')
+ self.assertEqual(self.builds[1].name, 'project-test2')
+ self.assertEqual(self.builds[2].name, 'project-test1')
+ self.assertEqual(self.builds[3].name, 'project-test2')
+ self.assertEqual(self.builds[4].name, 'project-test1')
+ self.assertEqual(self.builds[5].name, 'project-test2')
+
+ self.assertTrue(self.builds[0].hasChanges(A))
+ self.assertFalse(self.builds[0].hasChanges(B))
+ self.assertFalse(self.builds[0].hasChanges(C))
+
+ self.assertTrue(self.builds[2].hasChanges(A))
+ self.assertTrue(self.builds[2].hasChanges(B))
+ self.assertFalse(self.builds[2].hasChanges(C))
+
+ self.assertTrue(self.builds[4].hasChanges(A))
+ self.assertTrue(self.builds[4].hasChanges(B))
+ self.assertTrue(self.builds[4].hasChanges(C))
+
+ self.executor_server.release()
+ self.waitUntilSettled()
+
+ self.assertEqual(A.data['status'], 'MERGED')
+ self.assertEqual(A.reported, 2)
+ self.assertEqual(B.data['status'], 'MERGED')
+ self.assertEqual(B.reported, 2)
+ self.assertEqual(C.data['status'], 'MERGED')
+ self.assertEqual(C.reported, 2)
+ # The promote should be a noop, so no canceled jobs
+ self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
+ self.assertEqual(len(self.history), 9)
+
+ def test_promote_check(self):
+ """Test that a change can be promoted via the admin web interface"""
+ self.executor_server.hold_jobs_in_build = True
+ # Make a patch series so that we have some non-live items in
+ # the pipeline and we can make sure they are not promoted.
+ A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+ B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
+ B.setDependsOn(A, 1)
+ C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
+ C.setDependsOn(B, 1)
+
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
+ self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
+
+ self.waitUntilSettled()
+
+ tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
+ items = [i for i in tenant.layout.pipelines['check'].getAllItems()
+ if i.live]
+ enqueue_times = {}
+ for item in items:
+ enqueue_times[str(item.change)] = item.enqueue_time
+
+ # REST API
+ args = {'pipeline': 'check',
+ 'changes': ['2,1', '3,1']}
+ authz = {'iss': 'zuul_operator',
+ 'aud': 'zuul.example.com',
+ 'sub': 'testuser',
+ 'zuul': {
+ 'admin': ['tenant-one', ],
+ },
+ 'exp': time.time() + 3600,
+ 'iat': time.time()}
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
+ algorithm='HS256')
+ req = self.post_url(
+ 'api/tenant/tenant-one/promote',
+ headers={'Authorization': 'Bearer %s' % token},
+ json=args)
+ self.assertEqual(200, req.status_code, req.text)
+ data = req.json()
+ self.assertEqual(True, data)
+ self.waitUntilSettled()
+
+ # ensure that enqueue times are durable
+ items = [i for i in tenant.layout.pipelines['check'].getAllItems()
+ if i.live]
+ for item in items:
+ self.assertEqual(
+ enqueue_times[str(item.change)], item.enqueue_time)
+
+ # We can't reliably test for side effects in the check
+ # pipeline since the change queues are independent, so we
+ # directly examine the queues.
+ queue_items = [(item.change.number, item.live) for item in
+ tenant.layout.pipelines['check'].getAllItems()]
+ expected = [('1', False),
+ ('2', True),
+ ('1', False),
+ ('2', False),
+ ('3', True),
+ ('1', True)]
+ self.assertEqual(expected, queue_items)
+
+ self.executor_server.release('.*-merge')
+ self.waitUntilSettled()
+ self.executor_server.release()
+ self.waitUntilSettled()
+ # No jobs should be canceled
+ self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
+ self.assertEqual(len(self.history), 9)
def test_tenant_authorizations_override(self):
"""Test that user gets overriden tenant authz if allowed"""