def setUp(self): fd, self.db_filename = tempfile.mkstemp(prefix='bodhi-testing-', suffix='.db') db_path = 'sqlite:///%s' % self.db_filename # The BUILD_ID environment variable is set by Jenkins and allows us to # detect if # we are running the tests in jenkins or not # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-below if os.environ.get('BUILD_ID'): faitout = 'http://209.132.184.152/faitout/' try: import requests req = requests.get('%s/new' % faitout) if req.status_code == 200: db_path = req.text print 'Using faitout at: %s' % db_path except: pass engine = create_engine(db_path) Base.metadata.create_all(engine) self.db_factory = transactional_session_maker(engine) with self.db_factory() as session: populate(session) assert session.query(Update).count() == 1 self.koji = buildsys.get_session() self.koji.clear() # clear out our dev introspection self.msg = makemsg() self.tempdir = tempfile.mkdtemp('bodhi') self.masher = Masher(FakeHub(), db_factory=self.db_factory, mash_dir=self.tempdir)
def setUp(self): fd, self.db_filename = tempfile.mkstemp(prefix="bodhi-testing-", suffix=".db") db_path = "sqlite:///%s" % self.db_filename # The BUILD_ID environment variable is set by Jenkins and allows us to # detect if # we are running the tests in jenkins or not # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-below if os.environ.get("BUILD_ID"): faitout = "http://209.132.184.152/faitout/" try: import requests req = requests.get("%s/new" % faitout) if req.status_code == 200: db_path = req.text print "Using faitout at: %s" % db_path except: pass engine = create_engine(db_path) Base.metadata.create_all(engine) self.db_factory = transactional_session_maker(engine) with self.db_factory() as session: populate(session) assert session.query(Update).count() == 1 self.koji = buildsys.get_session() self.koji.clear() # clear out our dev introspection self.msg = makemsg() self.tempdir = tempfile.mkdtemp("bodhi") self.masher = Masher(FakeHub(), db_factory=self.db_factory, mash_dir=self.tempdir)
def test_invalid_signature(self, publish): """Make sure the masher ignores messages that aren't signed with the appropriate releng cert """ fakehub = FakeHub() fakehub.config['releng_fedmsg_certname'] = 'foo' self.masher = Masher(fakehub, db_factory=self.db_factory) self.masher.consume(self.msg) # Make sure the update did not get locked with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertFalse(up.locked) # Ensure mashtask.start never got sent self.assertEquals(len(publish.call_args_list), 0)
def test_invalid_signature(self, publish): """Make sure the masher ignores messages that aren't signed with the appropriate releng cert """ fakehub = FakeHub() fakehub.config["releng_fedmsg_certname"] = "foo" self.masher = Masher(fakehub, db_factory=self.db_factory) self.masher.consume(self.msg) # Make sure the update did not get locked with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertFalse(up.locked) # Ensure mashtask.start never got sent self.assertEquals(len(publish.call_args_list), 0)
class TestMasher(unittest.TestCase): def setUp(self): fd, self.db_filename = tempfile.mkstemp(prefix='bodhi-testing-', suffix='.db') db_path = 'sqlite:///%s' % self.db_filename # The BUILD_ID environment variable is set by Jenkins and allows us to # detect if # we are running the tests in jenkins or not # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-below if os.environ.get('BUILD_ID'): faitout = 'http://209.132.184.152/faitout/' try: import requests req = requests.get('%s/new' % faitout) if req.status_code == 200: db_path = req.text print 'Using faitout at: %s' % db_path except: pass engine = create_engine(db_path) Base.metadata.create_all(engine) self.db_factory = transactional_session_maker(engine) with self.db_factory() as session: populate(session) assert session.query(Update).count() == 1 self.koji = buildsys.get_session() self.koji.clear() # clear out our dev introspection self.msg = makemsg() self.tempdir = tempfile.mkdtemp('bodhi') self.masher = Masher(FakeHub(), db_factory=self.db_factory, mash_dir=self.tempdir) def tearDown(self): shutil.rmtree(self.tempdir) try: os.remove(self.db_filename) except: pass def set_stable_request(self, title): with self.db_factory() as session: query = session.query(Update).filter_by(title=title) update = query.one() update.request = UpdateRequest.stable session.flush() @mock.patch('bodhi.notifications.publish') def test_invalid_signature(self, publish): """Make sure the masher ignores messages that aren't signed with the appropriate releng cert """ fakehub = FakeHub() fakehub.config['releng_fedmsg_certname'] = 'foo' self.masher = Masher(fakehub, db_factory=self.db_factory) self.masher.consume(self.msg) # Make sure the update did not get locked with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertFalse(up.locked) # Ensure mashtask.start never got sent self.assertEquals(len(publish.call_args_list), 0) @mock.patch('bodhi.notifications.publish') def test_push_invalid_update(self, publish): msg = makemsg() msg['body']['msg']['updates'] = 'invalidbuild-1.0-1.fc17' self.masher.consume(msg) self.assertEquals(len(publish.call_args_list), 1) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch.object(MasherThread, 'verify_updates', mock_exc) @mock.patch('bodhi.notifications.publish') def test_update_locking(self, publish, *args): with self.db_factory() as session: up = session.query(Update).one() self.assertFalse(up.locked) self.masher.consume(self.msg) # Ensure that fedmsg was called 4 times self.assertEquals(len(publish.call_args_list), 3) # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", msg=dict(success=False, repo='f17-updates-testing'), force=True) with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertTrue(up.locked) # Ensure we can't set a request from bodhi.exceptions import LockedUpdateException try: up.set_request(session, UpdateRequest.stable, u'bodhi') assert False, 'Set the request on a locked update' except LockedUpdateException: pass @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_tags(self, publish, *args): # Make the build a buildroot override as well title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: release = session.query(Update).one().release build = session.query(Build).one() nvr = build.nvr pending_testing_tag = release.pending_testing_tag override_tag = release.override_tag self.koji.__tagged__[title] = [ release.override_tag, pending_testing_tag ] # Start the push self.masher.consume(self.msg) # Ensure that fedmsg was called 3 times self.assertEquals(len(publish.call_args_list), 4) # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", msg=dict(success=True, repo='f17-updates-testing'), force=True) # Ensure our single update was moved self.assertEquals(len(self.koji.__moved__), 1) self.assertEquals(len(self.koji.__added__), 0) self.assertEquals(self.koji.__moved__[0], (u'f17-updates-candidate', u'f17-updates-testing', u'bodhi-2.0-1.fc17')) # The override tag won't get removed until it goes to stable self.assertEquals(self.koji.__untag__[0], (pending_testing_tag, nvr)) self.assertEquals(len(self.koji.__untag__), 1) with self.db_factory() as session: # Set the update request to stable and the release to pending up = session.query(Update).one() up.release.state = ReleaseState.pending up.request = UpdateRequest.stable self.koji.clear() self.masher.consume(self.msg) # Ensure that stable updates to pending releases get their # tags added, not removed self.assertEquals(len(self.koji.__moved__), 0) self.assertEquals(len(self.koji.__added__), 1) self.assertEquals(self.koji.__added__[0], (u'f17', u'bodhi-2.0-1.fc17')) self.assertEquals(self.koji.__untag__[0], (override_tag, u'bodhi-2.0-1.fc17')) # Check that the override got expired with self.db_factory() as session: ovrd = session.query(BuildrootOverride).one() self.assertIsNotNone(ovrd.expired_date) # Check that the request_complete method got run up = session.query(Update).one() self.assertIsNone(up.request) def test_statefile(self): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) t.id = 'f17-updates-testing' t.init_state() t.save_state() self.assertTrue(os.path.exists(t.mash_lock)) with file(t.mash_lock) as f: state = json.load(f) try: self.assertEquals(state, { u'updates': [u'bodhi-2.0-1.fc17'], u'completed_repos': [] }) finally: t.remove_state() @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.mail._send_mail') def test_testing_digest(self, mail, *args): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None self.assertEquals( t.testing_digest[u'Fedora 17'][u'bodhi-2.0-1.fc17'], """\ ================================================================================ libseccomp-2.1.0-1.fc20 (FEDORA-%s-a3bbe1a8f2) Enhanced seccomp library -------------------------------------------------------------------------------- Update Information: Useful details! -------------------------------------------------------------------------------- References: [ 1 ] Bug #12345 - None https://bugzilla.redhat.com/show_bug.cgi?id=12345 [ 2 ] CVE-1985-0110 http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-1985-0110 -------------------------------------------------------------------------------- """ % time.strftime('%Y')) mail.assert_called_with(config.get('bodhi_email'), config.get('fedora_test_announce_list'), mock.ANY) assert len(mail.mock_calls) == 2, len(mail.mock_calls) body = mail.mock_calls[1][1][2] assert body.startswith( 'From: [email protected]\r\nTo: %s\r\nSubject: Fedora 17 updates-testing report\r\n\r\nThe following builds have been pushed to Fedora 17 updates-testing\n\n bodhi-2.0-1.fc17\n\nDetails about builds:\n\n\n================================================================================\n libseccomp-2.1.0-1.fc20 (FEDORA-%s-a3bbe1a8f2)\n Enhanced seccomp library\n--------------------------------------------------------------------------------\nUpdate Information:\n\nUseful details!\n--------------------------------------------------------------------------------\nReferences:\n\n [ 1 ] Bug #12345 - None\n https://bugzilla.redhat.com/show_bug.cgi?id=12345\n [ 2 ] CVE-1985-0110\n http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-1985-0110\n--------------------------------------------------------------------------------\n\n' % (config.get('fedora_test_announce_list'), time.strftime('%Y'))), repr(body) def test_sanity_check(self): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) t.id = 'f17-updates-testing' t.init_path() # test without any arches try: t.sanity_check_repo() assert False, "Sanity check didn't fail with empty dir" except: pass # test with valid repodata for arch in ('i386', 'x86_64', 'armhfp'): repo = os.path.join(t.path, t.id, arch) os.makedirs(repo) mkmetadatadir(repo) t.sanity_check_repo() # test with truncated/busted repodata xml = os.path.join(t.path, t.id, 'i386', 'repodata', 'repomd.xml') repomd = open(xml).read() with open(xml, 'w') as f: f.write(repomd[:-10]) from bodhi.exceptions import RepodataException try: t.sanity_check_repo() assert False, 'Busted metadata passed' except RepodataException: pass def test_stage(self): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) t.id = 'f17-updates-testing' t.init_path() t.stage_repo() stage_dir = config.get('mash_stage_dir') link = os.path.join(stage_dir, t.id) self.assertTrue(os.path.islink(link)) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_security_update_priority(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() user = db.query(User).first() # Create a security update for a different release release = Release( name=u'F18', long_name=u'Fedora 18', id_prefix=u'FEDORA', version=u'18', dist_tag=u'f18', stable_tag=u'f18-updates', testing_tag=u'f18-updates-testing', candidate_tag=u'f18-updates-candidate', pending_testing_tag=u'f18-updates-testing-pending', pending_stable_tag=u'f18-updates-pending', override_tag=u'f18-override', branch=u'f18') db.add(release) build = Build(nvr=u'bodhi-2.0-1.fc18', release=release, package=up.builds[0].package) db.add(build) update = Update(title=u'bodhi-2.0-1.fc18', builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u'Useful details!', release=release) update.type = UpdateType.security db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg['body']['msg']['updates'] += ['bodhi-2.0-1.fc18'] self.masher.consume(self.msg) # Ensure that F18 runs before F17 calls = publish.mock_calls # Order of fedmsgs at the the moment: # masher.start # mashing f18 # complete.stable (for each update) # errata.publish # mashtask.complete # mashing f17 # complete.testing # mashtask.complete self.assertEquals( calls[1], mock.call(force=True, msg={ 'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18'] }, topic='mashtask.mashing')) self.assertEquals( calls[4], mock.call(force=True, msg={ 'success': True, 'repo': 'f18-updates' }, topic='mashtask.complete')) self.assertEquals( calls[5], mock.call(force=True, msg={ 'repo': u'f17-updates-testing', 'updates': [u'bodhi-2.0-1.fc17'] }, topic='mashtask.mashing')) self.assertEquals( calls[-1], mock.call(force=True, msg={ 'success': True, 'repo': 'f17-updates-testing' }, topic='mashtask.complete')) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_security_update_priority_testing(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() up.type = UpdateType.security up.request = UpdateRequest.testing user = db.query(User).first() # Create a security update for a different release release = Release( name=u'F18', long_name=u'Fedora 18', id_prefix=u'FEDORA', version=u'18', dist_tag=u'f18', stable_tag=u'f18-updates', testing_tag=u'f18-updates-testing', candidate_tag=u'f18-updates-candidate', pending_testing_tag=u'f18-updates-testing-pending', pending_stable_tag=u'f18-updates-pending', override_tag=u'f18-override', branch=u'f18') db.add(release) build = Build(nvr=u'bodhi-2.0-1.fc18', release=release, package=up.builds[0].package) db.add(build) update = Update(title=u'bodhi-2.0-1.fc18', builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u'Useful details!', release=release) update.type = UpdateType.enhancement db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg['body']['msg']['updates'] += ['bodhi-2.0-1.fc18'] self.masher.consume(self.msg) # Ensure that F17 updates-testing runs before F18 calls = publish.mock_calls self.assertEquals( calls[1], mock.call(msg={ 'repo': u'f17-updates-testing', 'updates': [u'bodhi-2.0-1.fc17'] }, force=True, topic='mashtask.mashing')) self.assertEquals( calls[3], mock.call(msg={ 'success': True, 'repo': 'f17-updates-testing' }, force=True, topic='mashtask.complete')) self.assertEquals( calls[4], mock.call(msg={ 'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18'] }, force=True, topic='mashtask.mashing')) self.assertEquals( calls[-1], mock.call(msg={ 'success': True, 'repo': 'f18-updates' }, force=True, topic='mashtask.complete')) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_security_updates_parallel(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() up.type = UpdateType.security up.status = UpdateStatus.testing up.request = UpdateRequest.stable user = db.query(User).first() # Create a security update for a different release release = Release( name=u'F18', long_name=u'Fedora 18', id_prefix=u'FEDORA', version=u'18', dist_tag=u'f18', stable_tag=u'f18-updates', testing_tag=u'f18-updates-testing', candidate_tag=u'f18-updates-candidate', pending_testing_tag=u'f18-updates-testing-pending', pending_stable_tag=u'f18-updates-pending', override_tag=u'f18-override', branch=u'f18') db.add(release) build = Build(nvr=u'bodhi-2.0-1.fc18', release=release, package=up.builds[0].package) db.add(build) update = Update(title=u'bodhi-2.0-1.fc18', builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u'Useful details!', release=release) update.type = UpdateType.security db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg['body']['msg']['updates'] += ['bodhi-2.0-1.fc18'] self.masher.consume(self.msg) # Ensure that F18 and F17 run in parallel calls = publish.mock_calls if calls[1] == mock.call(msg={ 'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18'] }, force=True, topic='mashtask.mashing'): self.assertEquals( calls[2], mock.call(msg={ 'repo': u'f17-updates', 'updates': [u'bodhi-2.0-1.fc17'] }, force=True, topic='mashtask.mashing')) elif calls[1] == self.assertEquals( calls[1], mock.call(msg={ 'repo': u'f17-updates', 'updates': [u'bodhi-2.0-1.fc17'] }, force=True, topic='mashtask.mashing')): self.assertEquals( calls[2], mock.call(msg={ 'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18'] }, force=True, topic='mashtask.mashing')) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.util.cmd') def test_update_comps(self, cmd, *args): cmd.return_value = '', '', 0 self.masher.consume(self.msg) self.assertIn(mock.call(['git', 'pull'], mock.ANY), cmd.mock_calls) self.assertIn(mock.call(['make'], mock.ANY), cmd.mock_calls) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_mash(self, cmd, publish, *args): cmd.return_value = '', '', 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates')) publish.assert_any_call(topic='update.complete.stable', force=True, msg=mock.ANY) self.assertIn(mock.call(['mash'] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state['completed_repos']), 1) @mock.patch(**mock_failed_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_failed_gating(self, cmd, publish, *args): cmd.return_value = '', '', 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates')) publish.assert_any_call(topic='update.eject', msg=mock.ANY, force=True) self.assertIn(mock.call(['mash'] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state['completed_repos']), 1) @mock.patch(**mock_absent_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_absent_gating(self, cmd, publish, *args): cmd.return_value = '', '', 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates')) publish.assert_any_call(topic='update.eject', msg=mock.ANY, force=True) self.assertIn(mock.call(['mash'] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state['completed_repos']), 1) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') @mock.patch('bodhi.bugs.bugtracker.modified') @mock.patch('bodhi.bugs.bugtracker.on_qa') def test_modify_testing_bugs(self, on_qa, modified, *args): self.masher.consume(self.msg) on_qa.assert_called_once_with( 12345, u"bodhi-2.0-1.fc17 has been pushed to the Fedora 17 testing repository. If problems still persist, please make note of it in this bug report.\nIf you want to test the update, you can install it with\n$ su -c 'dnf --enablerepo=updates-testing update bodhi'\nYou can provide feedback for this update here: http://0.0.0.0:6543/updates/FEDORA-%s-a3bbe1a8f2" % time.localtime().tm_year) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') @mock.patch('bodhi.bugs.bugtracker.comment') @mock.patch('bodhi.bugs.bugtracker.close') def test_modify_stable_bugs(self, close, comment, *args): self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None close.assert_called_with(12345, versions=dict(bodhi=u'bodhi-2.0-1.fc17')) comment.assert_called_with( 12345, u'bodhi-2.0-1.fc17 has been pushed to the Fedora 17 stable repository. If problems still persist, please make note of it in this bug report.' ) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_status_comment_testing(self, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 3) self.assertEquals(up.comments[-1]['text'], u'This update has been pushed to testing.') @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_status_comment_stable(self, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.stable self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 3) self.assertEquals(up.comments[-1]['text'], u'This update has been pushed to stable.') @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_get_security_updates(self, *args): build = u'bodhi-2.0-1.fc17' t = MasherThread(u'F17', u'testing', [build], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session u = session.query(Update).one() u.type = UpdateType.security u.status = UpdateStatus.testing u.request = None release = session.query(Release).one() updates = t.get_security_updates(release.long_name) self.assertEquals(len(updates), 1) self.assertEquals(updates[0].title, build) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_unlock_updates(self, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.stable self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.locked, False) self.assertEquals(up.status, UpdateStatus.stable) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_resume_push(self, *args): title = self.msg['body']['msg']['updates'][0] with mock.patch.object(MasherThread, 'generate_testing_digest', mock_exc): with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.testing up.status = UpdateStatus.pending # Simulate a failed push self.masher.consume(self.msg) # Ensure that the update hasn't changed state with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.request, UpdateRequest.testing) self.assertEquals(up.status, UpdateStatus.pending) # Resume the push self.msg['body']['msg']['resume'] = True self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.status, UpdateStatus.testing) self.assertEquals(up.request, None) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_stable_requirements_met_during_push(self, *args): """ Test reaching the stablekarma threshold while the update is being pushed to testing """ title = self.msg['body']['msg']['updates'][0] # Simulate a failed push with mock.patch.object(MasherThread, 'verify_updates', mock_exc): with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.testing up.status = UpdateStatus.pending self.assertEquals(up.stable_karma, 3) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() # Ensure the update is still locked and in testing self.assertEquals(up.locked, True) self.assertEquals(up.status, UpdateStatus.pending) self.assertEquals(up.request, UpdateRequest.testing) # Have the update reach the stable karma threshold self.assertEquals(up.karma, 1) up.comment(session, u"foo", 1, u'foo') self.assertEquals(up.karma, 2) self.assertEquals(up.request, UpdateRequest.testing) up.comment(session, u"foo", 1, u'bar') self.assertEquals(up.karma, 3) self.assertEquals(up.request, UpdateRequest.testing) up.comment(session, u"foo", 1, u'biz') self.assertEquals(up.request, UpdateRequest.testing) self.assertEquals(up.karma, 4) # finish push and unlock updates self.msg['body']['msg']['resume'] = True self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.comment(session, u"foo", 1, u'baz') self.assertEquals(up.karma, 5) # Ensure the masher set the autokarma once the push is done self.assertEquals(up.locked, False) self.assertEquals(up.request, UpdateRequest.stable) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_push_timestamps(self, publish, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: release = session.query(Update).one().release pending_testing_tag = release.pending_testing_tag self.koji.__tagged__[title] = [ release.override_tag, pending_testing_tag ] # Start the push self.masher.consume(self.msg) with self.db_factory() as session: # Set the update request to stable and the release to pending up = session.query(Update).one() self.assertIsNotNone(up.date_testing) self.assertIsNone(up.date_stable) up.request = UpdateRequest.stable # Ensure that fedmsg was called 3 times self.assertEquals(len(publish.call_args_list), 4) # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates-testing')) self.koji.clear() self.masher.consume(self.msg) with self.db_factory() as session: # Check that the request_complete method got run up = session.query(Update).one() self.assertIsNone(up.request) self.assertIsNotNone(up.date_stable)
class TestMasher(unittest.TestCase): def setUp(self): fd, self.db_filename = tempfile.mkstemp(prefix="bodhi-testing-", suffix=".db") db_path = "sqlite:///%s" % self.db_filename # The BUILD_ID environment variable is set by Jenkins and allows us to # detect if # we are running the tests in jenkins or not # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-below if os.environ.get("BUILD_ID"): faitout = "http://209.132.184.152/faitout/" try: import requests req = requests.get("%s/new" % faitout) if req.status_code == 200: db_path = req.text print "Using faitout at: %s" % db_path except: pass engine = create_engine(db_path) Base.metadata.create_all(engine) self.db_factory = transactional_session_maker(engine) with self.db_factory() as session: populate(session) assert session.query(Update).count() == 1 self.koji = buildsys.get_session() self.koji.clear() # clear out our dev introspection self.msg = makemsg() self.tempdir = tempfile.mkdtemp("bodhi") self.masher = Masher(FakeHub(), db_factory=self.db_factory, mash_dir=self.tempdir) def tearDown(self): shutil.rmtree(self.tempdir) try: os.remove(self.db_filename) except: pass def set_stable_request(self, title): with self.db_factory() as session: query = session.query(Update).filter_by(title=title) update = query.one() update.request = UpdateRequest.stable session.flush() @mock.patch("bodhi.notifications.publish") def test_invalid_signature(self, publish): """Make sure the masher ignores messages that aren't signed with the appropriate releng cert """ fakehub = FakeHub() fakehub.config["releng_fedmsg_certname"] = "foo" self.masher = Masher(fakehub, db_factory=self.db_factory) self.masher.consume(self.msg) # Make sure the update did not get locked with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertFalse(up.locked) # Ensure mashtask.start never got sent self.assertEquals(len(publish.call_args_list), 0) @mock.patch("bodhi.notifications.publish") def test_push_invalid_update(self, publish): msg = makemsg() msg["body"]["msg"]["updates"] = "invalidbuild-1.0-1.fc17" self.masher.consume(msg) self.assertEquals(len(publish.call_args_list), 1) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch.object(MasherThread, "verify_updates", mock_exc) @mock.patch("bodhi.notifications.publish") def test_update_locking(self, publish, *args): with self.db_factory() as session: up = session.query(Update).one() self.assertFalse(up.locked) self.masher.consume(self.msg) # Ensure that fedmsg was called 4 times self.assertEquals(len(publish.call_args_list), 3) # Also, ensure we reported success publish.assert_called_with( topic="mashtask.complete", msg=dict(success=False, repo="f17-updates-testing"), force=True ) with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertTrue(up.locked) # Ensure we can't set a request from bodhi.exceptions import LockedUpdateException try: up.set_request(session, UpdateRequest.stable, u"bodhi") assert False, "Set the request on a locked update" except LockedUpdateException: pass @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") def test_tags(self, publish, *args): # Make the build a buildroot override as well title = self.msg["body"]["msg"]["updates"][0] with self.db_factory() as session: release = session.query(Update).one().release build = session.query(Build).one() nvr = build.nvr pending_testing_tag = release.pending_testing_tag override_tag = release.override_tag self.koji.__tagged__[title] = [release.override_tag, pending_testing_tag] # Start the push self.masher.consume(self.msg) # Ensure that fedmsg was called 3 times self.assertEquals(len(publish.call_args_list), 4) # Also, ensure we reported success publish.assert_called_with( topic="mashtask.complete", msg=dict(success=True, repo="f17-updates-testing"), force=True ) # Ensure our single update was moved self.assertEquals(len(self.koji.__moved__), 1) self.assertEquals(len(self.koji.__added__), 0) self.assertEquals( self.koji.__moved__[0], (u"f17-updates-candidate", u"f17-updates-testing", u"bodhi-2.0-1.fc17") ) # The override tag won't get removed until it goes to stable self.assertEquals(self.koji.__untag__[0], (pending_testing_tag, nvr)) self.assertEquals(len(self.koji.__untag__), 1) with self.db_factory() as session: # Set the update request to stable and the release to pending up = session.query(Update).one() up.release.state = ReleaseState.pending up.request = UpdateRequest.stable self.koji.clear() self.masher.consume(self.msg) # Ensure that stable updates to pending releases get their # tags added, not removed self.assertEquals(len(self.koji.__moved__), 0) self.assertEquals(len(self.koji.__added__), 1) self.assertEquals(self.koji.__added__[0], (u"f17", u"bodhi-2.0-1.fc17")) self.assertEquals(self.koji.__untag__[0], (override_tag, u"bodhi-2.0-1.fc17")) # Check that the override got expired with self.db_factory() as session: ovrd = session.query(BuildrootOverride).one() self.assertIsNotNone(ovrd.expired_date) # Check that the request_complete method got run up = session.query(Update).one() self.assertIsNone(up.request) def test_statefile(self): t = MasherThread(u"F17", u"testing", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) t.id = "f17-updates-testing" t.init_state() t.save_state() self.assertTrue(os.path.exists(t.mash_lock)) with file(t.mash_lock) as f: state = json.load(f) try: self.assertEquals(state, {u"updates": [u"bodhi-2.0-1.fc17"], u"completed_repos": []}) finally: t.remove_state() @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.mail._send_mail") def test_testing_digest(self, mail, *args): t = MasherThread(u"F17", u"testing", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None self.assertEquals( t.testing_digest[u"Fedora 17"][u"bodhi-2.0-1.fc17"], """\ ================================================================================ libseccomp-2.1.0-1.fc20 (FEDORA-%s-a3bbe1a8f2) Enhanced seccomp library -------------------------------------------------------------------------------- Update Information: Useful details! -------------------------------------------------------------------------------- References: [ 1 ] Bug #12345 - None https://bugzilla.redhat.com/show_bug.cgi?id=12345 [ 2 ] CVE-1985-0110 http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-1985-0110 -------------------------------------------------------------------------------- """ % time.strftime("%Y"), ) mail.assert_called_with(config.get("bodhi_email"), config.get("fedora_test_announce_list"), mock.ANY) assert len(mail.mock_calls) == 2, len(mail.mock_calls) body = mail.mock_calls[1][1][2] assert body.startswith( "From: [email protected]\r\nTo: %s\r\nX-Bodhi: fedoraproject.org\r\nSubject: Fedora 17 updates-testing report\r\n\r\nThe following builds have been pushed to Fedora 17 updates-testing\n\n bodhi-2.0-1.fc17\n\nDetails about builds:\n\n\n================================================================================\n libseccomp-2.1.0-1.fc20 (FEDORA-%s-a3bbe1a8f2)\n Enhanced seccomp library\n--------------------------------------------------------------------------------\nUpdate Information:\n\nUseful details!\n--------------------------------------------------------------------------------\nReferences:\n\n [ 1 ] Bug #12345 - None\n https://bugzilla.redhat.com/show_bug.cgi?id=12345\n [ 2 ] CVE-1985-0110\n http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-1985-0110\n--------------------------------------------------------------------------------\n\n" % (config.get("fedora_test_announce_list"), time.strftime("%Y")) ), repr(body) def test_sanity_check(self): t = MasherThread(u"F17", u"testing", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) t.id = "f17-updates-testing" t.init_path() # test without any arches try: t.sanity_check_repo() assert False, "Sanity check didn't fail with empty dir" except: pass # test with valid repodata for arch in ("i386", "x86_64", "armhfp"): repo = os.path.join(t.path, t.id, arch) os.makedirs(repo) mkmetadatadir(repo) t.sanity_check_repo() # test with truncated/busted repodata xml = os.path.join(t.path, t.id, "i386", "repodata", "repomd.xml") repomd = open(xml).read() with open(xml, "w") as f: f.write(repomd[:-10]) from bodhi.exceptions import RepodataException try: t.sanity_check_repo() assert False, "Busted metadata passed" except RepodataException: pass def test_stage(self): t = MasherThread(u"F17", u"testing", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) t.id = "f17-updates-testing" t.init_path() t.stage_repo() stage_dir = config.get("mash_stage_dir") link = os.path.join(stage_dir, t.id) self.assertTrue(os.path.islink(link)) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") def test_security_update_priority(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() user = db.query(User).first() # Create a security update for a different release release = Release( name=u"F18", long_name=u"Fedora 18", id_prefix=u"FEDORA", version=u"18", dist_tag=u"f18", stable_tag=u"f18-updates", testing_tag=u"f18-updates-testing", candidate_tag=u"f18-updates-candidate", pending_testing_tag=u"f18-updates-testing-pending", pending_stable_tag=u"f18-updates-pending", override_tag=u"f18-override", branch=u"f18", ) db.add(release) build = Build(nvr=u"bodhi-2.0-1.fc18", release=release, package=up.builds[0].package) db.add(build) update = Update( title=u"bodhi-2.0-1.fc18", builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u"Useful details!", release=release, ) update.type = UpdateType.security db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg["body"]["msg"]["updates"] += ["bodhi-2.0-1.fc18"] self.masher.consume(self.msg) # Ensure that F18 runs before F17 calls = publish.mock_calls # Order of fedmsgs at the the moment: # masher.start # mashing f18 # complete.stable (for each update) # errata.publish # mashtask.complete # mashing f17 # complete.testing # mashtask.complete self.assertEquals( calls[1], mock.call( force=True, msg={"repo": u"f18-updates", "updates": [u"bodhi-2.0-1.fc18"]}, topic="mashtask.mashing" ), ) self.assertEquals( calls[4], mock.call(force=True, msg={"success": True, "repo": "f18-updates"}, topic="mashtask.complete") ) self.assertEquals( calls[5], mock.call( force=True, msg={"repo": u"f17-updates-testing", "updates": [u"bodhi-2.0-1.fc17"]}, topic="mashtask.mashing", ), ) self.assertEquals( calls[-1], mock.call(force=True, msg={"success": True, "repo": "f17-updates-testing"}, topic="mashtask.complete"), ) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") def test_security_update_priority_testing(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() up.type = UpdateType.security up.request = UpdateRequest.testing user = db.query(User).first() # Create a security update for a different release release = Release( name=u"F18", long_name=u"Fedora 18", id_prefix=u"FEDORA", version=u"18", dist_tag=u"f18", stable_tag=u"f18-updates", testing_tag=u"f18-updates-testing", candidate_tag=u"f18-updates-candidate", pending_testing_tag=u"f18-updates-testing-pending", pending_stable_tag=u"f18-updates-pending", override_tag=u"f18-override", branch=u"f18", ) db.add(release) build = Build(nvr=u"bodhi-2.0-1.fc18", release=release, package=up.builds[0].package) db.add(build) update = Update( title=u"bodhi-2.0-1.fc18", builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u"Useful details!", release=release, ) update.type = UpdateType.enhancement db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg["body"]["msg"]["updates"] += ["bodhi-2.0-1.fc18"] self.masher.consume(self.msg) # Ensure that F17 updates-testing runs before F18 calls = publish.mock_calls self.assertEquals( calls[1], mock.call( msg={"repo": u"f17-updates-testing", "updates": [u"bodhi-2.0-1.fc17"]}, force=True, topic="mashtask.mashing", ), ) self.assertEquals( calls[3], mock.call(msg={"success": True, "repo": "f17-updates-testing"}, force=True, topic="mashtask.complete"), ) self.assertEquals( calls[4], mock.call( msg={"repo": u"f18-updates", "updates": [u"bodhi-2.0-1.fc18"]}, force=True, topic="mashtask.mashing" ), ) self.assertEquals( calls[-1], mock.call(msg={"success": True, "repo": "f18-updates"}, force=True, topic="mashtask.complete") ) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") def test_security_updates_parallel(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() up.type = UpdateType.security up.status = UpdateStatus.testing up.request = UpdateRequest.stable user = db.query(User).first() # Create a security update for a different release release = Release( name=u"F18", long_name=u"Fedora 18", id_prefix=u"FEDORA", version=u"18", dist_tag=u"f18", stable_tag=u"f18-updates", testing_tag=u"f18-updates-testing", candidate_tag=u"f18-updates-candidate", pending_testing_tag=u"f18-updates-testing-pending", pending_stable_tag=u"f18-updates-pending", override_tag=u"f18-override", branch=u"f18", ) db.add(release) build = Build(nvr=u"bodhi-2.0-1.fc18", release=release, package=up.builds[0].package) db.add(build) update = Update( title=u"bodhi-2.0-1.fc18", builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u"Useful details!", release=release, ) update.type = UpdateType.security db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg["body"]["msg"]["updates"] += ["bodhi-2.0-1.fc18"] self.masher.consume(self.msg) # Ensure that F18 and F17 run in parallel calls = publish.mock_calls if calls[1] == mock.call( msg={"repo": u"f18-updates", "updates": [u"bodhi-2.0-1.fc18"]}, force=True, topic="mashtask.mashing" ): self.assertEquals( calls[2], mock.call( msg={"repo": u"f17-updates", "updates": [u"bodhi-2.0-1.fc17"]}, force=True, topic="mashtask.mashing" ), ) elif calls[1] == self.assertEquals( calls[1], mock.call( msg={"repo": u"f17-updates", "updates": [u"bodhi-2.0-1.fc17"]}, force=True, topic="mashtask.mashing" ), ): self.assertEquals( calls[2], mock.call( msg={"repo": u"f18-updates", "updates": [u"bodhi-2.0-1.fc18"]}, force=True, topic="mashtask.mashing" ), ) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.util.cmd") def test_update_comps(self, cmd, *args): cmd.return_value = "", "", 0 self.masher.consume(self.msg) self.assertIn(mock.call(["git", "pull"], mock.ANY), cmd.mock_calls) self.assertIn(mock.call(["make"], mock.ANY), cmd.mock_calls) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_mash(self, cmd, publish, *args): cmd.return_value = "", "", 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request("bodhi-2.0-1.fc17") t = MasherThread(u"F17", u"stable", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo="f17-updates")) publish.assert_any_call(topic="update.complete.stable", force=True, msg=mock.ANY) self.assertIn(mock.call(["mash"] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state["completed_repos"]), 1) @mock.patch(**mock_failed_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_failed_gating(self, cmd, publish, *args): cmd.return_value = "", "", 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request("bodhi-2.0-1.fc17") t = MasherThread(u"F17", u"stable", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo="f17-updates")) publish.assert_any_call(topic="update.eject", msg=mock.ANY, force=True) self.assertIn(mock.call(["mash"] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state["completed_repos"]), 1) @mock.patch(**mock_absent_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_absent_gating(self, cmd, publish, *args): cmd.return_value = "", "", 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request("bodhi-2.0-1.fc17") t = MasherThread(u"F17", u"stable", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo="f17-updates")) publish.assert_any_call(topic="update.eject", msg=mock.ANY, force=True) self.assertIn(mock.call(["mash"] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state["completed_repos"]), 1) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") @mock.patch("bodhi.bugs.bugtracker.modified") @mock.patch("bodhi.bugs.bugtracker.on_qa") def test_modify_testing_bugs(self, on_qa, modified, *args): self.masher.consume(self.msg) on_qa.assert_called_once_with( 12345, u"bodhi-2.0-1.fc17 has been pushed to the Fedora 17 testing repository. If problems still persist, please make note of it in this bug report.\nIf you want to test the update, you can install it with\n$ su -c 'dnf --enablerepo=updates-testing update bodhi'\nYou can provide feedback for this update here: http://0.0.0.0:6543/updates/FEDORA-%s-a3bbe1a8f2" % time.localtime().tm_year, ) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") @mock.patch("bodhi.bugs.bugtracker.comment") @mock.patch("bodhi.bugs.bugtracker.close") def test_modify_stable_bugs(self, close, comment, *args): self.set_stable_request("bodhi-2.0-1.fc17") t = MasherThread(u"F17", u"stable", [u"bodhi-2.0-1.fc17"], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None close.assert_called_with(12345, versions=dict(bodhi=u"bodhi-2.0-1.fc17")) comment.assert_called_with( 12345, u"bodhi-2.0-1.fc17 has been pushed to the Fedora 17 stable repository. If problems still persist, please make note of it in this bug report.", ) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_status_comment_testing(self, *args): title = self.msg["body"]["msg"]["updates"][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 3) self.assertEquals(up.comments[-1]["text"], u"This update has been pushed to testing.") @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_status_comment_stable(self, *args): title = self.msg["body"]["msg"]["updates"][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.stable self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 3) self.assertEquals(up.comments[-1]["text"], u"This update has been pushed to stable.") @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") def test_get_security_updates(self, *args): build = u"bodhi-2.0-1.fc17" t = MasherThread(u"F17", u"testing", [build], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session u = session.query(Update).one() u.type = UpdateType.security u.status = UpdateStatus.testing u.request = None release = session.query(Release).one() updates = t.get_security_updates(release.long_name) self.assertEquals(len(updates), 1) self.assertEquals(updates[0].title, build) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_unlock_updates(self, *args): title = self.msg["body"]["msg"]["updates"][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.stable self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.locked, False) self.assertEquals(up.status, UpdateStatus.stable) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_resume_push(self, *args): title = self.msg["body"]["msg"]["updates"][0] with mock.patch.object(MasherThread, "generate_testing_digest", mock_exc): with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.testing up.status = UpdateStatus.pending # Simulate a failed push self.masher.consume(self.msg) # Ensure that the update hasn't changed state with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.request, UpdateRequest.testing) self.assertEquals(up.status, UpdateStatus.pending) # Resume the push self.msg["body"]["msg"]["resume"] = True self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.status, UpdateStatus.testing) self.assertEquals(up.request, None) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") @mock.patch("bodhi.util.cmd") def test_stable_requirements_met_during_push(self, *args): """ Test reaching the stablekarma threshold while the update is being pushed to testing """ title = self.msg["body"]["msg"]["updates"][0] # Simulate a failed push with mock.patch.object(MasherThread, "verify_updates", mock_exc): with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.testing up.status = UpdateStatus.pending self.assertEquals(up.stable_karma, 3) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() # Ensure the update is still locked and in testing self.assertEquals(up.locked, True) self.assertEquals(up.status, UpdateStatus.pending) self.assertEquals(up.request, UpdateRequest.testing) # Have the update reach the stable karma threshold self.assertEquals(up.karma, 1) up.comment(session, u"foo", 1, u"foo") self.assertEquals(up.karma, 2) self.assertEquals(up.request, UpdateRequest.testing) up.comment(session, u"foo", 1, u"bar") self.assertEquals(up.karma, 3) self.assertEquals(up.request, UpdateRequest.testing) up.comment(session, u"foo", 1, u"biz") self.assertEquals(up.request, UpdateRequest.testing) self.assertEquals(up.karma, 4) # finish push and unlock updates self.msg["body"]["msg"]["resume"] = True self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.comment(session, u"foo", 1, u"baz") self.assertEquals(up.karma, 5) # Ensure the masher set the autokarma once the push is done self.assertEquals(up.locked, False) self.assertEquals(up.request, UpdateRequest.stable) @mock.patch(**mock_taskotron_results) @mock.patch("bodhi.consumers.masher.MasherThread.update_comps") @mock.patch("bodhi.consumers.masher.MashThread.run") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_mash") @mock.patch("bodhi.consumers.masher.MasherThread.sanity_check_repo") @mock.patch("bodhi.consumers.masher.MasherThread.stage_repo") @mock.patch("bodhi.consumers.masher.MasherThread.generate_updateinfo") @mock.patch("bodhi.consumers.masher.MasherThread.wait_for_sync") @mock.patch("bodhi.notifications.publish") def test_push_timestamps(self, publish, *args): title = self.msg["body"]["msg"]["updates"][0] with self.db_factory() as session: release = session.query(Update).one().release pending_testing_tag = release.pending_testing_tag self.koji.__tagged__[title] = [release.override_tag, pending_testing_tag] # Start the push self.masher.consume(self.msg) with self.db_factory() as session: # Set the update request to stable and the release to pending up = session.query(Update).one() self.assertIsNotNone(up.date_testing) self.assertIsNone(up.date_stable) up.request = UpdateRequest.stable # Ensure that fedmsg was called 3 times self.assertEquals(len(publish.call_args_list), 4) # Also, ensure we reported success publish.assert_called_with( topic="mashtask.complete", force=True, msg=dict(success=True, repo="f17-updates-testing") ) self.koji.clear() self.masher.consume(self.msg) with self.db_factory() as session: # Check that the request_complete method got run up = session.query(Update).one() self.assertIsNone(up.request) self.assertIsNotNone(up.date_stable)
class TestMasher(unittest.TestCase): def setUp(self): fd, self.db_filename = tempfile.mkstemp(prefix='bodhi-testing-', suffix='.db') db_path = 'sqlite:///%s' % self.db_filename # The BUILD_ID environment variable is set by Jenkins and allows us to # detect if # we are running the tests in jenkins or not # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-below if os.environ.get('BUILD_ID'): faitout = 'http://209.132.184.152/faitout/' try: import requests req = requests.get('%s/new' % faitout) if req.status_code == 200: db_path = req.text print 'Using faitout at: %s' % db_path except: pass engine = create_engine(db_path) Base.metadata.create_all(engine) self.db_factory = transactional_session_maker(engine) with self.db_factory() as session: populate(session) assert session.query(Update).count() == 1 self.koji = buildsys.get_session() self.koji.clear() # clear out our dev introspection self.msg = makemsg() self.tempdir = tempfile.mkdtemp('bodhi') self.masher = Masher(FakeHub(), db_factory=self.db_factory, mash_dir=self.tempdir) def tearDown(self): shutil.rmtree(self.tempdir) try: os.remove(self.db_filename) except: pass def set_stable_request(self, title): with self.db_factory() as session: query = session.query(Update).filter_by(title=title) update = query.one() update.request = UpdateRequest.stable session.flush() @mock.patch('bodhi.notifications.publish') def test_invalid_signature(self, publish): """Make sure the masher ignores messages that aren't signed with the appropriate releng cert """ with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() up.locked = False fakehub = FakeHub() fakehub.config['releng_fedmsg_certname'] = 'foo' self.masher = Masher(fakehub, db_factory=self.db_factory) self.masher.consume(self.msg) # Make sure the update did not get locked with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertFalse(up.locked) # Ensure mashtask.start never got sent self.assertEquals(len(publish.call_args_list), 0) @mock.patch('bodhi.notifications.publish') def test_push_invalid_update(self, publish): msg = makemsg() msg['body']['msg']['updates'] = 'invalidbuild-1.0-1.fc17' self.masher.consume(msg) self.assertEquals(len(publish.call_args_list), 1) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch.object(MasherThread, 'verify_updates', mock_exc) @mock.patch('bodhi.notifications.publish') def test_update_locking(self, publish, *args): with self.db_factory() as session: up = session.query(Update).one() up.locked = False self.masher.consume(self.msg) # Ensure that fedmsg was called 4 times self.assertEquals(len(publish.call_args_list), 3) # Also, ensure we reported success publish.assert_called_with( topic="mashtask.complete", msg=dict(success=False, repo='f17-updates-testing'), force=True) with self.db_factory() as session: # Ensure that the update was locked up = session.query(Update).one() self.assertTrue(up.locked) # Ensure we can't set a request from bodhi.exceptions import LockedUpdateException try: up.set_request(session, UpdateRequest.stable, u'bodhi') assert False, 'Set the request on a locked update' except LockedUpdateException: pass @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_tags(self, publish, *args): # Make the build a buildroot override as well title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: release = session.query(Update).one().release build = session.query(Build).one() nvr = build.nvr pending_testing_tag = release.pending_testing_tag override_tag = release.override_tag self.koji.__tagged__[title] = [release.override_tag, pending_testing_tag] # Start the push self.masher.consume(self.msg) # Ensure that fedmsg was called 3 times self.assertEquals(len(publish.call_args_list), 4) # Also, ensure we reported success publish.assert_called_with( topic="mashtask.complete", msg=dict(success=True, repo='f17-updates-testing'), force=True) # Ensure our single update was moved self.assertEquals(len(self.koji.__moved__), 1) self.assertEquals(len(self.koji.__added__), 0) self.assertEquals(self.koji.__moved__[0], (u'f17-updates-candidate', u'f17-updates-testing', u'bodhi-2.0-1.fc17')) # The override tag won't get removed until it goes to stable self.assertEquals(self.koji.__untag__[0], (pending_testing_tag, nvr)) self.assertEquals(len(self.koji.__untag__), 1) with self.db_factory() as session: # Set the update request to stable and the release to pending up = session.query(Update).one() up.release.state = ReleaseState.pending up.request = UpdateRequest.stable self.koji.clear() self.masher.consume(self.msg) # Ensure that stable updates to pending releases get their # tags added, not removed self.assertEquals(len(self.koji.__moved__), 0) self.assertEquals(len(self.koji.__added__), 1) self.assertEquals(self.koji.__added__[0], (u'f17', u'bodhi-2.0-1.fc17')) self.assertEquals(self.koji.__untag__[0], (override_tag, u'bodhi-2.0-1.fc17')) # Check that the override got expired with self.db_factory() as session: ovrd = session.query(BuildrootOverride).one() self.assertIsNotNone(ovrd.expired_date) # Check that the request_complete method got run up = session.query(Update).one() self.assertIsNone(up.request) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_tag_ordering(self, publish, *args): """ Test pushing an batch of updates with multiple builds for the same package. Ensure that the latest version is tagged last. """ otherbuild = 'bodhi-2.0-2.fc17' self.msg['body']['msg']['updates'].insert(0, otherbuild) with self.db_factory() as session: firstupdate = session.query(Update).filter_by(title=self.msg['body']['msg']['updates'][1]).one() build = Build(nvr=otherbuild, package=firstupdate.builds[0].package) session.add(build) update = Update(title=otherbuild, builds=[build], type=UpdateType.bugfix, request=UpdateRequest.testing, notes=u'second update', user=firstupdate.user, release=firstupdate.release) session.add(update) session.flush() # Start the push self.masher.consume(self.msg) # Ensure that fedmsg was called 5 times self.assertEquals(len(publish.call_args_list), 5) # Also, ensure we reported success publish.assert_called_with( topic="mashtask.complete", msg=dict(success=True, repo='f17-updates-testing'), force=True) # Ensure our two updates were moved self.assertEquals(len(self.koji.__moved__), 2) self.assertEquals(len(self.koji.__added__), 0) # Ensure the most recent version is tagged last in order to be the 'koji latest-pkg' self.assertEquals(self.koji.__moved__[0], (u'f17-updates-candidate', u'f17-updates-testing', u'bodhi-2.0-1.fc17')) self.assertEquals(self.koji.__moved__[1], (u'f17-updates-candidate', u'f17-updates-testing', u'bodhi-2.0-2.fc17')) def test_statefile(self): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) t.id = 'f17-updates-testing' t.init_state() t.save_state() self.assertTrue(os.path.exists(t.mash_lock)) with file(t.mash_lock) as f: state = json.load(f) try: self.assertEquals(state, {u'updates': [u'bodhi-2.0-1.fc17'], u'completed_repos': []}) finally: t.remove_state() @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.mail._send_mail') def test_testing_digest(self, mail, *args): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None self.assertEquals(t.testing_digest[u'Fedora 17'][u'bodhi-2.0-1.fc17'], """\ ================================================================================ libseccomp-2.1.0-1.fc20 (FEDORA-%s-a3bbe1a8f2) Enhanced seccomp library -------------------------------------------------------------------------------- Update Information: Useful details! -------------------------------------------------------------------------------- References: [ 1 ] Bug #12345 - None https://bugzilla.redhat.com/show_bug.cgi?id=12345 [ 2 ] CVE-1985-0110 http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-1985-0110 -------------------------------------------------------------------------------- """ % time.strftime('%Y')) mail.assert_called_with(config.get('bodhi_email'), config.get('fedora_test_announce_list'), mock.ANY) assert len(mail.mock_calls) == 2, len(mail.mock_calls) body = mail.mock_calls[1][1][2] assert body.startswith('From: [email protected]\r\nTo: %s\r\nX-Bodhi: fedoraproject.org\r\nSubject: Fedora 17 updates-testing report\r\n\r\nThe following builds have been pushed to Fedora 17 updates-testing\n\n bodhi-2.0-1.fc17\n\nDetails about builds:\n\n\n================================================================================\n libseccomp-2.1.0-1.fc20 (FEDORA-%s-a3bbe1a8f2)\n Enhanced seccomp library\n--------------------------------------------------------------------------------\nUpdate Information:\n\nUseful details!\n--------------------------------------------------------------------------------\nReferences:\n\n [ 1 ] Bug #12345 - None\n https://bugzilla.redhat.com/show_bug.cgi?id=12345\n [ 2 ] CVE-1985-0110\n http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-1985-0110\n--------------------------------------------------------------------------------\n\n' % (config.get('fedora_test_announce_list'), time.strftime('%Y'))), repr(body) def test_sanity_check(self): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) t.id = 'f17-updates-testing' t.init_path() # test without any arches try: t.sanity_check_repo() assert False, "Sanity check didn't fail with empty dir" except: pass # test with valid repodata for arch in ('i386', 'x86_64', 'armhfp'): repo = os.path.join(t.path, t.id, arch) os.makedirs(repo) mkmetadatadir(repo) t.sanity_check_repo() # test with truncated/busted repodata xml = os.path.join(t.path, t.id, 'i386', 'repodata', 'repomd.xml') repomd = open(xml).read() with open(xml, 'w') as f: f.write(repomd[:-10]) from bodhi.exceptions import RepodataException try: t.sanity_check_repo() assert False, 'Busted metadata passed' except RepodataException: pass def test_stage(self): t = MasherThread(u'F17', u'testing', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) t.id = 'f17-updates-testing' t.init_path() t.stage_repo() stage_dir = config.get('mash_stage_dir') link = os.path.join(stage_dir, t.id) self.assertTrue(os.path.islink(link)) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_security_update_priority(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() user = db.query(User).first() # Create a security update for a different release release = Release( name=u'F18', long_name=u'Fedora 18', id_prefix=u'FEDORA', version=u'18', dist_tag=u'f18', stable_tag=u'f18-updates', testing_tag=u'f18-updates-testing', candidate_tag=u'f18-updates-candidate', pending_testing_tag=u'f18-updates-testing-pending', pending_stable_tag=u'f18-updates-pending', override_tag=u'f18-override', branch=u'f18') db.add(release) build = Build(nvr=u'bodhi-2.0-1.fc18', release=release, package=up.builds[0].package) db.add(build) update = Update( title=u'bodhi-2.0-1.fc18', builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u'Useful details!', release=release) update.type = UpdateType.security db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg['body']['msg']['updates'] += ['bodhi-2.0-1.fc18'] self.masher.consume(self.msg) # Ensure that F18 runs before F17 calls = publish.mock_calls # Order of fedmsgs at the the moment: # masher.start # mashing f18 # complete.stable (for each update) # errata.publish # mashtask.complete # mashing f17 # complete.testing # mashtask.complete self.assertEquals(calls[1], mock.call( force=True, msg={'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18']}, topic='mashtask.mashing')) self.assertEquals(calls[4], mock.call( force=True, msg={'success': True, 'repo': 'f18-updates'}, topic='mashtask.complete')) self.assertEquals(calls[5], mock.call( force=True, msg={'repo': u'f17-updates-testing', 'updates': [u'bodhi-2.0-1.fc17']}, topic='mashtask.mashing')) self.assertEquals(calls[-1], mock.call( force=True, msg={'success': True, 'repo': 'f17-updates-testing'}, topic='mashtask.complete')) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_security_update_priority_testing(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() up.type = UpdateType.security up.request = UpdateRequest.testing user = db.query(User).first() # Create a security update for a different release release = Release( name=u'F18', long_name=u'Fedora 18', id_prefix=u'FEDORA', version=u'18', dist_tag=u'f18', stable_tag=u'f18-updates', testing_tag=u'f18-updates-testing', candidate_tag=u'f18-updates-candidate', pending_testing_tag=u'f18-updates-testing-pending', pending_stable_tag=u'f18-updates-pending', override_tag=u'f18-override', branch=u'f18') db.add(release) build = Build(nvr=u'bodhi-2.0-1.fc18', release=release, package=up.builds[0].package) db.add(build) update = Update( title=u'bodhi-2.0-1.fc18', builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u'Useful details!', release=release) update.type = UpdateType.enhancement db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg['body']['msg']['updates'] += ['bodhi-2.0-1.fc18'] self.masher.consume(self.msg) # Ensure that F17 updates-testing runs before F18 calls = publish.mock_calls self.assertEquals(calls[1], mock.call( msg={'repo': u'f17-updates-testing', 'updates': [u'bodhi-2.0-1.fc17']}, force=True, topic='mashtask.mashing')) self.assertEquals(calls[3], mock.call( msg={'success': True, 'repo': 'f17-updates-testing'}, force=True, topic='mashtask.complete')) self.assertEquals(calls[4], mock.call( msg={'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18']}, force=True, topic='mashtask.mashing')) self.assertEquals(calls[-1], mock.call( msg={'success': True, 'repo': 'f18-updates'}, force=True, topic='mashtask.complete')) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_security_updates_parallel(self, publish, *args): with self.db_factory() as db: up = db.query(Update).one() up.type = UpdateType.security up.status = UpdateStatus.testing up.request = UpdateRequest.stable user = db.query(User).first() # Create a security update for a different release release = Release( name=u'F18', long_name=u'Fedora 18', id_prefix=u'FEDORA', version=u'18', dist_tag=u'f18', stable_tag=u'f18-updates', testing_tag=u'f18-updates-testing', candidate_tag=u'f18-updates-candidate', pending_testing_tag=u'f18-updates-testing-pending', pending_stable_tag=u'f18-updates-pending', override_tag=u'f18-override', branch=u'f18') db.add(release) build = Build(nvr=u'bodhi-2.0-1.fc18', release=release, package=up.builds[0].package) db.add(build) update = Update( title=u'bodhi-2.0-1.fc18', builds=[build], user=user, status=UpdateStatus.testing, request=UpdateRequest.stable, notes=u'Useful details!', release=release) update.type = UpdateType.security db.add(update) # Wipe out the tag cache so it picks up our new release Release._tag_cache = None self.msg['body']['msg']['updates'] += ['bodhi-2.0-1.fc18'] self.masher.consume(self.msg) # Ensure that F18 and F17 run in parallel calls = publish.mock_calls if calls[1] == mock.call( msg={'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18']}, force=True, topic='mashtask.mashing'): self.assertEquals(calls[2], mock.call( msg={'repo': u'f17-updates', 'updates': [u'bodhi-2.0-1.fc17']}, force=True, topic='mashtask.mashing')) elif calls[1] == self.assertEquals(calls[1], mock.call( msg={'repo': u'f17-updates', 'updates': [u'bodhi-2.0-1.fc17']}, force=True, topic='mashtask.mashing')): self.assertEquals(calls[2], mock.call( msg={'repo': u'f18-updates', 'updates': [u'bodhi-2.0-1.fc18']}, force=True, topic='mashtask.mashing')) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.util.cmd') def test_update_comps(self, cmd, *args): cmd.return_value = '', '', 0 self.masher.consume(self.msg) self.assertIn(mock.call(['git', 'pull'], mock.ANY), cmd.mock_calls) self.assertIn(mock.call(['make'], mock.ANY), cmd.mock_calls) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_mash(self, cmd, publish, *args): cmd.return_value = '', '', 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates')) publish.assert_any_call(topic='update.complete.stable', force=True, msg=mock.ANY) self.assertIn(mock.call(['mash'] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state['completed_repos']), 1) @mock.patch(**mock_failed_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_failed_gating(self, cmd, publish, *args): cmd.return_value = '', '', 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates')) publish.assert_any_call(topic='update.eject', msg=mock.ANY, force=True) self.assertIn(mock.call(['mash'] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state['completed_repos']), 1) @mock.patch(**mock_absent_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_absent_gating(self, cmd, publish, *args): cmd.return_value = '', '', 0 # Set the request to stable right out the gate so we can test gating self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None # Also, ensure we reported success publish.assert_called_with(topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates')) publish.assert_any_call(topic='update.eject', msg=mock.ANY, force=True) self.assertIn(mock.call(['mash'] + [mock.ANY] * 7), cmd.mock_calls) self.assertEquals(len(t.state['completed_repos']), 1) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') @mock.patch('bodhi.bugs.bugtracker.modified') @mock.patch('bodhi.bugs.bugtracker.on_qa') def test_modify_testing_bugs(self, on_qa, modified, *args): self.masher.consume(self.msg) on_qa.assert_called_once_with(12345, u'bodhi-2.0-1.fc17 has been pushed to the Fedora 17 testing repository. If problems still persist, please make note of it in this bug report.\nSee https://fedoraproject.org/wiki/QA:Updates_Testing for\ninstructions on how to install test updates.\nYou can provide feedback for this update here: http://0.0.0.0:6543/updates/FEDORA-2016-a3bbe1a8f2') @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') @mock.patch('bodhi.bugs.bugtracker.comment') @mock.patch('bodhi.bugs.bugtracker.close') def test_modify_stable_bugs(self, close, comment, *args): self.set_stable_request('bodhi-2.0-1.fc17') t = MasherThread(u'F17', u'stable', [u'bodhi-2.0-1.fc17'], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session t.work() t.db = None close.assert_called_with( 12345, versions=dict(bodhi=u'bodhi-2.0-1.fc17')) comment.assert_called_with(12345, u'bodhi-2.0-1.fc17 has been pushed to the Fedora 17 stable repository. If problems still persist, please make note of it in this bug report.') @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_status_comment_testing(self, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 3) self.assertEquals(up.comments[-1]['text'], u'This update has been pushed to testing.') @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_status_comment_stable(self, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.stable self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(len(up.comments), 3) self.assertEquals(up.comments[-1]['text'], u'This update has been pushed to stable.') @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_get_security_updates(self, *args): build = u'bodhi-2.0-1.fc17' t = MasherThread(u'F17', u'testing', [build], log, self.db_factory, self.tempdir) with self.db_factory() as session: t.db = session u = session.query(Update).one() u.type = UpdateType.security u.status = UpdateStatus.testing u.request = None release = session.query(Release).one() updates = t.get_security_updates(release.long_name) self.assertEquals(len(updates), 1) self.assertEquals(updates[0].title, build) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_unlock_updates(self, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.stable self.assertEquals(len(up.comments), 2) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.locked, False) self.assertEquals(up.status, UpdateStatus.stable) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_resume_push(self, *args): title = self.msg['body']['msg']['updates'][0] with mock.patch.object(MasherThread, 'generate_testing_digest', mock_exc): with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.testing up.status = UpdateStatus.pending # Simulate a failed push self.masher.consume(self.msg) # Ensure that the update hasn't changed state with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.request, UpdateRequest.testing) self.assertEquals(up.status, UpdateStatus.pending) # Resume the push self.msg['body']['msg']['resume'] = True self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() self.assertEquals(up.status, UpdateStatus.testing) self.assertEquals(up.request, None) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') @mock.patch('bodhi.util.cmd') def test_stable_requirements_met_during_push(self, *args): """ Test reaching the stablekarma threshold while the update is being pushed to testing """ title = self.msg['body']['msg']['updates'][0] # Simulate a failed push with mock.patch.object(MasherThread, 'verify_updates', mock_exc): with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.request = UpdateRequest.testing up.status = UpdateStatus.pending self.assertEquals(up.stable_karma, 3) self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() # Ensure the update is still locked and in testing self.assertEquals(up.locked, True) self.assertEquals(up.status, UpdateStatus.pending) self.assertEquals(up.request, UpdateRequest.testing) # Have the update reach the stable karma threshold self.assertEquals(up.karma, 1) up.comment(session, u"foo", 1, u'foo') self.assertEquals(up.karma, 2) self.assertEquals(up.request, UpdateRequest.testing) up.comment(session, u"foo", 1, u'bar') self.assertEquals(up.karma, 3) self.assertEquals(up.request, UpdateRequest.testing) up.comment(session, u"foo", 1, u'biz') self.assertEquals(up.request, UpdateRequest.testing) self.assertEquals(up.karma, 4) # finish push and unlock updates self.msg['body']['msg']['resume'] = True self.masher.consume(self.msg) with self.db_factory() as session: up = session.query(Update).filter_by(title=title).one() up.comment(session, u"foo", 1, u'baz') self.assertEquals(up.karma, 5) # Ensure the masher set the autokarma once the push is done self.assertEquals(up.locked, False) self.assertEquals(up.request, UpdateRequest.stable) @mock.patch(**mock_taskotron_results) @mock.patch('bodhi.consumers.masher.MasherThread.update_comps') @mock.patch('bodhi.consumers.masher.MashThread.run') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_mash') @mock.patch('bodhi.consumers.masher.MasherThread.sanity_check_repo') @mock.patch('bodhi.consumers.masher.MasherThread.stage_repo') @mock.patch('bodhi.consumers.masher.MasherThread.generate_updateinfo') @mock.patch('bodhi.consumers.masher.MasherThread.wait_for_sync') @mock.patch('bodhi.notifications.publish') def test_push_timestamps(self, publish, *args): title = self.msg['body']['msg']['updates'][0] with self.db_factory() as session: release = session.query(Update).one().release pending_testing_tag = release.pending_testing_tag self.koji.__tagged__[title] = [release.override_tag, pending_testing_tag] # Start the push self.masher.consume(self.msg) with self.db_factory() as session: # Set the update request to stable and the release to pending up = session.query(Update).one() self.assertIsNotNone(up.date_testing) self.assertIsNone(up.date_stable) up.request = UpdateRequest.stable # Ensure that fedmsg was called 3 times self.assertEquals(len(publish.call_args_list), 4) # Also, ensure we reported success publish.assert_called_with( topic="mashtask.complete", force=True, msg=dict(success=True, repo='f17-updates-testing')) self.koji.clear() self.masher.consume(self.msg) with self.db_factory() as session: # Check that the request_complete method got run up = session.query(Update).one() self.assertIsNone(up.request) self.assertIsNotNone(up.date_stable)