Exemplo n.º 1
0
 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', )])
Exemplo n.º 2
0
 def setup_canceller_with_no_filters(self):
     self.canceller = OldBuildCanceller('canceller', [])
     yield self.canceller.setServiceParent(self.master)
Exemplo n.º 3
0
 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)
Exemplo n.º 4
0
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([])
Exemplo n.º 5
0
 def test_check_builders_keys_not_list(self, name, value, error):
     with self.assertRaisesConfigError(error):
         OldBuildCanceller.check_filters([(value, SourceStampFilter())])
Exemplo n.º 6
0
 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)
Exemplo n.º 7
0
 def test_check_filters_valid(self, name, filters):
     OldBuildCanceller.check_filters(filters)