def test_check_filters_invalid_uple(self): with self.assertRaisesConfigError( 'must be a list of tuples each of which'): OldBuildCanceller.check_filters([('a', 'b', 'c')]) with self.assertRaisesConfigError( 'must be a list of tuples each of which'): OldBuildCanceller.check_filters([('a', )])
def setup_canceller_with_no_filters(self): self.canceller = OldBuildCanceller('canceller', []) yield self.canceller.setServiceParent(self.master)
def setup_canceller_with_filters(self): self.canceller = OldBuildCanceller('canceller', [ (['builder1'], SourceStampFilter(branch_eq=['branch1'])), (['builder2'], SourceStampFilter(branch_eq=['branch2'])), ]) yield self.canceller.setServiceParent(self.master)
class TestOldBuildCanceller(TestReactorMixin, unittest.TestCase): @defer.inlineCallbacks def setUp(self): self.setup_test_reactor() self.master = fakemaster.make_master(self, wantMq=True, wantData=True, wantDb=True) self.master.mq.verifyMessages = False self.insert_test_data() self._cancelled_build_ids = [] yield self.master.startService() def tearDown(self): return self.master.stopService() def create_ss_dict(self, project, codebase, repository, branch): # Changes have the same structure for the attributes that we're using, so we reuse this # function for changes. return { 'project': project, 'codebase': codebase, 'repository': repository, 'branch': branch, } def insert_test_data(self): self.master.db.insertTestData([ fakedb.Master(id=92), fakedb.Worker(id=13, name='wrk'), fakedb.Builder(id=79, name='builder1'), fakedb.Builder(id=80, name='builder2'), fakedb.Buildset(id=98, results=None, reason="reason98"), fakedb.BuildsetSourceStamp(buildsetid=98, sourcestampid=234), fakedb.SourceStamp(id=234, revision='revision1', project='project1', codebase='codebase1', repository='repository1', branch='branch1'), fakedb.BuildRequest(id=10, buildsetid=98, builderid=79), fakedb.Build(id=19, number=1, builderid=79, buildrequestid=10, workerid=13, masterid=92, results=None, state_string="state1"), fakedb.Buildset(id=99, results=None, reason="reason99"), fakedb.BuildsetSourceStamp(buildsetid=99, sourcestampid=235), fakedb.SourceStamp(id=235, revision='revision2', project='project2', codebase='codebase2', repository='repository2', branch='branch2'), fakedb.BuildRequest(id=11, buildsetid=99, builderid=80), fakedb.Build(id=20, number=1, builderid=80, buildrequestid=11, workerid=13, masterid=92, results=None, state_string="state2"), ]) @defer.inlineCallbacks def setup_canceller_with_filters(self): self.canceller = OldBuildCanceller('canceller', [ (['builder1'], SourceStampFilter(branch_eq=['branch1'])), (['builder2'], SourceStampFilter(branch_eq=['branch2'])), ]) yield self.canceller.setServiceParent(self.master) @defer.inlineCallbacks def setup_canceller_with_no_filters(self): self.canceller = OldBuildCanceller('canceller', []) yield self.canceller.setServiceParent(self.master) def assert_cancelled(self, cancellations): expected_productions = [] for kind, id in cancellations: if kind == 'build': expected_productions.append( (('control', 'builds', str(id), 'stop'), { 'reason': 'Build has been obsoleted by a newer commit' })) elif kind == 'breq': expected_productions.append( (('control', 'buildrequests', str(id), 'cancel'), { 'reason': 'Build request has been obsoleted by a newer commit' })) elif kind == 'buildrequests': brdict = yield self.master.db.buildrequests.getBuildRequest(id) expected_productions.append( (('buildrequests', str(id), 'cancel'), brdict)) else: raise Exception(f"Unknown cancellation type {kind}") self.master.mq.assertProductions(expected_productions) @defer.inlineCallbacks def test_cancel_build_after_new_commit(self): yield self.setup_canceller_with_filters() ss_dict = self.create_ss_dict('project1', 'codebase1', 'repository1', 'branch1') self.master.mq.callConsumer(('changes', '123', 'new'), ss_dict) self.assert_cancelled([('build', 19)]) self.master.mq.callConsumer(('changes', '124', 'new'), ss_dict) self.assert_cancelled([]) @defer.inlineCallbacks def test_build_finished_then_new_commit_no_cancel(self): yield self.setup_canceller_with_filters() ss_dict = self.create_ss_dict('project1', 'codebase1', 'repository1', 'branch1') self.master.mq.callConsumer(('builds', '19', 'finished'), {'buildid': 19}) self.master.mq.callConsumer(('changes', '123', 'new'), ss_dict) self.assert_cancelled([]) @defer.inlineCallbacks def test_reconfig_no_longer_matched_tracked_build_cancelled(self): yield self.setup_canceller_with_filters() ss_dict = self.create_ss_dict('project1', 'codebase1', 'repository1', 'branch1') yield self.canceller.reconfigService('canceller', []) self.master.mq.callConsumer(('changes', '123', 'new'), ss_dict) self.assert_cancelled([('build', 19)]) self.master.mq.callConsumer(('changes', '124', 'new'), ss_dict) self.assert_cancelled([]) @defer.inlineCallbacks def test_reconfig_defers_finished_builds_to_after_registration(self): # We need to make sure that during reconfiguration any finished build messages are not # acted before the build is tracked yield self.setup_canceller_with_no_filters() ss_dict1 = self.create_ss_dict('project1', 'codebase1', 'repository1', 'branch1') ss_dict2 = self.create_ss_dict('project2', 'codebase2', 'repository2', 'branch2') # Setup controllable blocking wait on canceller._on_build_new, _on_buildrequest_new on_build_new_d = defer.Deferred() on_build_new_original = self.canceller._on_build_new on_build_new_build_ids = [] on_buildrequest_new_d = defer.Deferred() on_buildrequest_new_original = self.canceller._on_buildrequest_new on_buildrequest_new_breq_ids = [] @defer.inlineCallbacks def waiting_on_build_new(key, build): on_build_new_build_ids.append(build['buildid']) if not on_build_new_d.called: yield on_build_new_d yield on_build_new_original(key, build) self.canceller._on_build_new = waiting_on_build_new @defer.inlineCallbacks def waiting_on_buildrequest_new(key, breq): on_buildrequest_new_breq_ids.append(breq['buildrequestid']) if not on_buildrequest_new_d.called: yield on_buildrequest_new_d yield on_buildrequest_new_original(key, breq) self.canceller._on_buildrequest_new = waiting_on_buildrequest_new # Start reconfig. We verify that we actually blocked in on_build_new d = self.canceller.reconfigService('canceller', [ { 'builders': ['builder1'], 'branch_eq': ['branch1'] }, { 'builders': ['builder2'], 'branch_eq': ['branch2'] }, ]) self.assertEqual(on_build_new_build_ids, []) self.assertEqual(on_buildrequest_new_breq_ids, [10]) self.assertFalse(d.called) # The build finish messages should be queued self.master.mq.callConsumer(('builds', '19', 'finished'), {'buildid': 19}) self.master.mq.callConsumer(('builds', '20', 'finished'), {'buildid': 20}) self.master.mq.callConsumer(('buildrequests', '10', 'complete'), {'buildrequestid': 10}) self.master.mq.callConsumer(('buildrequests', '11', 'complete'), {'buildrequestid': 11}) # Unblock reconfigService on_build_new_d.callback(None) on_buildrequest_new_d.callback(None) yield d self.assertEqual(on_build_new_build_ids, [19, 20]) self.assertEqual(on_buildrequest_new_breq_ids, [10, 11]) self.assertFalse(self.canceller._build_tracker.is_build_tracked(19)) self.assertFalse(self.canceller._build_tracker.is_build_tracked(20)) self.assertFalse( self.canceller._build_tracker.is_buildrequest_tracked(10)) self.assertFalse( self.canceller._build_tracker.is_buildrequest_tracked(11)) self.master.mq.callConsumer(('changes', '123', 'new'), ss_dict1) self.master.mq.callConsumer(('changes', '124', 'new'), ss_dict2) self.assert_cancelled([])
def test_check_builders_keys_not_list(self, name, value, error): with self.assertRaisesConfigError(error): OldBuildCanceller.check_filters([(value, SourceStampFilter())])
def test_check_filters_not_dict(self, name, value): with self.assertRaisesConfigError( 'The filters argument must be a list of tuples'): OldBuildCanceller.check_filters(value)
def test_check_filters_valid(self, name, filters): OldBuildCanceller.check_filters(filters)