Merge "Fix missing mutex release when aborting builds" into feature/zuulv3
diff --git a/tests/fixtures/config/single-tenant/git/layout-mutex-reconfiguration/playbooks/project-test1.yaml b/tests/fixtures/config/single-tenant/git/layout-mutex-reconfiguration/playbooks/project-test1.yaml
new file mode 100644
index 0000000..f679dce
--- /dev/null
+++ b/tests/fixtures/config/single-tenant/git/layout-mutex-reconfiguration/playbooks/project-test1.yaml
@@ -0,0 +1,2 @@
+- hosts: all
+ tasks: []
diff --git a/tests/fixtures/config/single-tenant/git/layout-mutex-reconfiguration/zuul.yaml b/tests/fixtures/config/single-tenant/git/layout-mutex-reconfiguration/zuul.yaml
new file mode 100644
index 0000000..12f1747
--- /dev/null
+++ b/tests/fixtures/config/single-tenant/git/layout-mutex-reconfiguration/zuul.yaml
@@ -0,0 +1,23 @@
+- pipeline:
+ name: check
+ manager: independent
+ source:
+ gerrit
+ trigger:
+ gerrit:
+ - event: patchset-created
+ success:
+ gerrit:
+ verified: 1
+ failure:
+ gerrit:
+ verified: -1
+
+- job:
+ name: project-test1
+
+- project:
+ name: org/project
+ check:
+ jobs:
+ - project-test1
diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py
index 03aff00..884bd9b 100755
--- a/tests/unit/test_scheduler.py
+++ b/tests/unit/test_scheduler.py
@@ -2250,6 +2250,66 @@
self.assertEqual(B.reported, 1)
self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
+ def test_mutex_abandon(self):
+ "Test abandon with job mutexes"
+ self.updateConfigLayout('layout-mutex')
+ self.sched.reconfigure(self.config)
+
+ self.launch_server.hold_jobs_in_build = True
+
+ tenant = self.sched.abide.tenants.get('openstack')
+ check_pipeline = tenant.layout.pipelines['check']
+
+ A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+ self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
+
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
+
+ self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
+ self.waitUntilSettled()
+
+ # The check pipeline should be empty
+ items = check_pipeline.getAllItems()
+ self.assertEqual(len(items), 0)
+
+ # The mutex should be released
+ self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
+
+ self.launch_server.hold_jobs_in_build = False
+ self.launch_server.release()
+ self.waitUntilSettled()
+
+ def test_mutex_reconfigure(self):
+ "Test reconfigure with job mutexes"
+ self.updateConfigLayout('layout-mutex')
+ self.sched.reconfigure(self.config)
+
+ self.launch_server.hold_jobs_in_build = True
+
+ A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+ self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
+
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
+
+ self.updateConfigLayout('layout-mutex-reconfiguration')
+ self.sched.reconfigure(self.config)
+ self.waitUntilSettled()
+
+ self.launch_server.release('project-test1')
+ self.waitUntilSettled()
+
+ # There should be no builds anymore
+ self.assertEqual(len(self.builds), 0)
+
+ # The mutex should be released
+ self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
+
def test_live_reconfiguration(self):
"Test that live reconfiguration works"
self.launch_server.hold_jobs_in_build = True
diff --git a/zuul/manager/__init__.py b/zuul/manager/__init__.py
index 6e5f567..18cf11b 100644
--- a/zuul/manager/__init__.py
+++ b/zuul/manager/__init__.py
@@ -409,6 +409,9 @@
except:
self.log.exception("Exception while canceling build %s "
"for change %s" % (build, item.change))
+ finally:
+ self.sched.mutex.release(build.build_set.item, build.job)
+
if not was_running:
try:
nodeset = build.build_set.getJobNodeSet(build.job.name)
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index c042e4f..1162f51 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -545,6 +545,8 @@
self.log.exception(
"Exception while canceling build %s "
"for change %s" % (build, item.change))
+ finally:
+ self.mutex.release(build.build_set.item, build.job)
def _reconfigureTenant(self, tenant):
# This is called from _doReconfigureEvent while holding the