From 135aaeb999facd7d90731de953ab9c52d4e3306f Mon Sep 17 00:00:00 2001 From: Qixiang Wan Date: May 15 2017 12:32:16 +0000 Subject: Update build state when receives module build state change message When receives a module build state change message, if the build is submitted by freshmaker, which means we can find it in db, update the its state in db. --- diff --git a/freshmaker/handlers/mbs.py b/freshmaker/handlers/mbs.py index 1c4a01c..e7f3c35 100644 --- a/freshmaker/handlers/mbs.py +++ b/freshmaker/handlers/mbs.py @@ -23,20 +23,28 @@ import requests -from freshmaker import log, conf, utils, pdc +from freshmaker import log, conf, utils, pdc, db, models from freshmaker.handlers import BaseHandler from freshmaker.events import ModuleBuilt, ModuleMetadataUpdated, RPMSpecUpdated +MBS_BUILD_STATES = { + "init": 0, + "wait": 1, + "build": 2, + "done": 3, + "failed": 4, + "ready": 5, +} + + class MBS(BaseHandler): name = "MBS" def can_handle(self, event): - # Handle only "ready" state of ModuleBuilt. # TODO: Handle only when something depends on # this module. - if (isinstance(event, ModuleBuilt) and - event.module_build_state == 5): + if isinstance(event, ModuleBuilt): return True if isinstance(event, ModuleMetadataUpdated): @@ -100,22 +108,41 @@ class MBS(BaseHandler): """ module_name = event.module_name module_stream = event.module_stream - - log.info("Triggering rebuild of modules depending on %s:%s " - "in MBS", module_name, module_stream) - - pdc_session = pdc.get_client_session(conf) - modules = pdc.get_latest_modules(pdc_session, - build_dep_name=module_name, - build_dep_stream=module_stream, - active='true') - for mod in modules: - name = mod['variant_name'] - version = mod['variant_version'] - commit_msg = "Bump to rebuild because of %s update" % module_name - build_id = self.bump_and_rebuild_module(name, version, commit_msg=commit_msg) - if build_id is not None: - self.record_build(event, name, 'module', build_id) + build_id = event.module_build_id + build_state = event.module_build_state + + # update build state if the build is submitted by Freshmaker + builds = db.session.query(models.ArtifactBuild).filter_by(build_id=build_id, + type=models.ARTIFACT_TYPES['module']).all() + if len(builds) > 1: + raise RuntimeError("Found duplicate module build '%s' in db" % build_id) + if len(builds) == 1: + build = builds[0] + if build_state in [MBS_BUILD_STATES['ready'], MBS_BUILD_STATES['failed']]: + log.info("Module build '%s' state changed in MBS, updating it in db.", build_id) + if build_state == MBS_BUILD_STATES['ready']: + build.state = models.BUILD_STATES['done'] + if build_state == MBS_BUILD_STATES['failed']: + build.state = models.BUILD_STATES['failed'] + db.session.commit() + + # Rebuild depending modules when state of ModuleBuilt is 'ready' + if build_state == MBS_BUILD_STATES['ready']: + log.info("Triggering rebuild of modules depending on %s:%s " + "in MBS", module_name, module_stream) + + pdc_session = pdc.get_client_session(conf) + modules = pdc.get_latest_modules(pdc_session, + build_dep_name=module_name, + build_dep_stream=module_stream, + active='true') + for mod in modules: + name = mod['variant_name'] + version = mod['variant_version'] + commit_msg = "Bump to rebuild because of %s update" % module_name + build_id = self.bump_and_rebuild_module(name, version, commit_msg=commit_msg) + if build_id is not None: + self.record_build(event, name, 'module', build_id) def handle_rpm_spec_updated(self, event): """ diff --git a/tests/test_mbs_handler.py b/tests/test_mbs_handler.py index a5bf068..7e89f46 100644 --- a/tests/test_mbs_handler.py +++ b/tests/test_mbs_handler.py @@ -51,28 +51,16 @@ class MBSHandlerTest(unittest.TestCase): event = events.BaseEvent.from_fedmsg(message['body']['topic'], message['body']) return event - def test_can_handle_module_built_ready_event(self): + def test_can_handle_module_built_event(self): """ - Tests MBS handler can handle modult build ready message + Tests MBS handler can handle module built message """ - - msg = helpers.ModuleBuiltMessage('testmodule', 'master', state='ready').produce() - event = self._get_event(msg) - - handler = MBS() - self.assertTrue(handler.can_handle(event)) - - def test_can_not_handle_module_built_non_ready_event(self): - """ - Tests MBS handler cannot handle modult build message which is not with - 'ready' state. - """ - for s in ['init', 'wait', 'build', 'done', 'failed']: - msg = helpers.ModuleBuiltMessage('testmodule', 'master', state=s).produce() + for state in ['init', 'wait', 'build', 'done', 'failed', 'ready']: + msg = helpers.ModuleBuiltMessage('testmodule', 'master', state=state).produce() event = self._get_event(msg) handler = MBS() - self.assertFalse(handler.can_handle(event)) + self.assertTrue(handler.can_handle(event)) @mock.patch('freshmaker.pdc.get_modules') @mock.patch('freshmaker.handlers.mbs.utils') @@ -260,5 +248,68 @@ class MBSHandlerTest(unittest.TestCase): self.assertEquals(builds[0].type, models.ARTIFACT_TYPES['module']) self.assertEquals(builds[0].build_id, 123) + @mock.patch('freshmaker.handlers.mbs.utils') + @mock.patch('freshmaker.handlers.mbs.pdc') + @mock.patch('freshmaker.handlers.mbs.conf') + def test_update_build_state_in_db(self, conf, pdc, utils): + """ + Test build state in db will be updated when receives module build + state change message. + """ + + # trigger a build on rpm spec updated event first + conf.git_base_url = "git://pkgs.fedoraproject.org" + + m = helpers.DistGitMessage('rpms', 'bash', 'master', '123') + m.add_changed_file('bash.spec', 1, 1) + msg = m.produce() + + event = self._get_event(msg) + + mod_info = helpers.PDCModuleInfo('testmodule', 'master', '20170412010101') + mod_info.add_rpm("bash-1.2.3-4.f26.rpm") + mod = mod_info.produce() + pdc.get_latest_modules.return_value = [mod] + + commitid = '9287eb8eb4c4c60f73b4a59f228a673846d940c6' + utils.get_commit_hash.return_value = commitid + + handler = MBS() + handler.rebuild_module = mock.Mock() + handler.rebuild_module.return_value = 123 + handler.handle(event) + self.assertEqual(handler.rebuild_module.call_args_list, + [mock.call('git://pkgs.fedoraproject.org/modules/testmodule.git?#%s' % commitid, 'master')]) + + event_list = models.Event.query.all() + self.assertEquals(len(event_list), 1) + self.assertEquals(event_list[0].message_id, event.msg_id) + builds = models.ArtifactBuild.query.all() + self.assertEquals(len(builds), 1) + self.assertEquals(builds[0].name, 'testmodule') + self.assertEquals(builds[0].type, models.ARTIFACT_TYPES['module']) + self.assertEquals(builds[0].build_id, 123) + self.assertEquals(builds[0].state, models.BUILD_STATES['build']) + + # update build state when receive module built messages + # build is failed + msg = helpers.ModuleBuiltMessage('testmodule', 'master', state='failed', build_id=123).produce() + event = self._get_event(msg) + handler.handle(event) + builds = models.ArtifactBuild.query.all() + self.assertEquals(len(builds), 1) + # build state updated to 'failed' + self.assertEquals(builds[0].state, models.BUILD_STATES['failed']) + + # build is ready + pdc.get_latest_modules.return_value = [] + msg = helpers.ModuleBuiltMessage('testmodule', 'master', state='ready', build_id=123).produce() + event = self._get_event(msg) + handler.handle(event) + builds = models.ArtifactBuild.query.all() + self.assertEquals(len(builds), 1) + # build state updated to 'done' + self.assertEquals(builds[0].state, models.BUILD_STATES['done']) + if __name__ == '__main__': unittest.main()