Implement autohold
Adds the 'autohold' client option, the scheduler implementation
of it, and a unit test for it.
The autohold is automatically removed from the in-memory data
structure once we've reached the number of requested runs of
the job.
Story: 2000905
Change-Id: Ieac0b5fee6801313fa23cce69520eb348735ad99
diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py
index 5dd3f4e..e38dd84 100755
--- a/tests/unit/test_scheduler.py
+++ b/tests/unit/test_scheduler.py
@@ -1434,6 +1434,58 @@
self.assertEqual(self.getJobFromHistory('project-test2').result,
'FAILURE')
+ @simple_layout('layouts/autohold.yaml')
+ def test_autohold(self):
+ A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+
+ client = zuul.rpcclient.RPCClient('127.0.0.1',
+ self.gearman_server.port)
+ self.addCleanup(client.shutdown)
+ r = client.autohold('tenant-one', 'org/project', 'project-test2', 1)
+ self.assertTrue(r)
+
+ self.executor_server.failJob('project-test2', A)
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+
+ self.waitUntilSettled()
+
+ self.assertEqual(A.data['status'], 'NEW')
+ self.assertEqual(A.reported, 1)
+ self.assertEqual(self.getJobFromHistory('project-test2').result,
+ 'FAILURE')
+
+ # Check nodepool for a held node
+ held_node = None
+ for node in self.fake_nodepool.getNodes():
+ if node['state'] == zuul.model.STATE_HOLD:
+ held_node = node
+ break
+ self.assertIsNotNone(held_node)
+
+ # Validate node has recorded the failed job
+ self.assertEqual(
+ held_node['hold_job'],
+ " ".join(['tenant-one',
+ 'review.example.com/org/project',
+ 'project-test2'])
+ )
+
+ # Another failed change should not hold any more nodes
+ B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
+ self.executor_server.failJob('project-test2', B)
+ self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+ self.assertEqual(B.data['status'], 'NEW')
+ self.assertEqual(B.reported, 1)
+ self.assertEqual(self.getJobFromHistory('project-test2').result,
+ 'FAILURE')
+
+ held_nodes = 0
+ for node in self.fake_nodepool.getNodes():
+ if node['state'] == zuul.model.STATE_HOLD:
+ held_nodes += 1
+ self.assertEqual(held_nodes, 1)
+
@simple_layout('layouts/three-projects.yaml')
def test_dependent_behind_dequeue(self):
# This particular test does a large amount of merges and needs a little