def test_gating_required_false(self): """Assert that test_gating_status is not updated if test_gating is not enabled.""" update = models.Update.query.filter_by(title=u'bodhi-2.0-1.fc17').one() update.test_gating_status = None hub = mock.MagicMock() hub.config = {'environment': 'environment', 'topic_prefix': 'topic_prefix'} h = updates.UpdatesHandler(hub) h.db_factory = base.TransactionalSessionMaker(self.Session) # Throw a bogus bug id in there to ensure it doesn't raise AssertionError. message = { 'topic': 'bodhi.update.request.testing', 'body': {'msg': {'update': {'alias': u'bodhi-2.0-1.fc17'}, 'new_bugs': []}}} with mock.patch('bodhi.server.models.util.greenwave_api_post') as mock_greenwave: greenwave_response = { 'policies_satisfied': False, 'summary': u'what have you done‽', 'applicable_policies': ['taskotron_release_critical_tasks'], 'unsatisfied_requirements': ['some arbitrary test you disagree with'] } mock_greenwave.return_value = greenwave_response h.consume(message) update = models.Update.query.filter_by(title=u'bodhi-2.0-1.fc17').one() self.assertIsNone(update.test_gating_status) self.assertIsNone(update.greenwave_summary_string)
def test_edited_update_bugs_in_update(self, work_on_bugs, fetch_test_cases): """ Test with a message that indicates that the update is being edited, and the list of bugs matches what UpdatesHandler finds in the database. """ hub = mock.MagicMock() hub.config = {'environment': 'environment', 'topic_prefix': 'topic_prefix'} h = updates.UpdatesHandler(hub) h.db_factory = base.TransactionalSessionMaker(self.Session) message = { 'topic': 'bodhi.update.edit', 'body': {'msg': {'update': {'alias': u'bodhi-2.0-1.fc17'}, 'new_bugs': ['12345']}}} h.consume(message) self.assertEqual(work_on_bugs.call_count, 1) self.assertTrue(isinstance(work_on_bugs.mock_calls[0][1][1], sqlalchemy.orm.session.Session)) self.assertEqual(work_on_bugs.mock_calls[0][1][2].title, u'bodhi-2.0-1.fc17') self.assertEqual([b.bug_id for b in work_on_bugs.mock_calls[0][1][3]], [12345]) self.assertEqual(fetch_test_cases.call_count, 1) self.assertTrue(isinstance(fetch_test_cases.mock_calls[0][1][1], sqlalchemy.orm.session.Session))
def test_edited_update_bug_not_in_update(self, work_on_bugs, fetch_test_cases): """ Test with a message that indicates that the update is being edited, and the list of bugs contains one that UpdatesHandler does not find in the database. """ hub = mock.MagicMock() hub.config = { 'environment': 'environment', 'topic_prefix': 'topic_prefix' } h = updates.UpdatesHandler(hub) h.db_factory = base.TransactionalSessionMaker(self.Session) message = { 'topic': 'bodhi.update.edit', 'body': { 'msg': { 'update': { 'alias': u'bodhi-2.0-1.fc17' }, 'new_bugs': ['12345', '123456'] } } } self.assertRaises(AssertionError, h.consume, message) self.assertEqual(work_on_bugs.call_count, 0) self.assertEqual(fetch_test_cases.call_count, 0)
def test_consume_from_tag(self): """ Assert that update created from tag is handled correctly when message is received. Update status is changed to testing and corresponding message is sent. """ self.handler.db_factory = base.TransactionalSessionMaker(self.Session) update = self.db.query(Update).filter( Build.nvr == 'bodhi-2.0-1.fc17').one() update.from_tag = "f30-side-tag" update.status = UpdateStatus.pending update.release.composed_by_bodhi = False update.builds[0].signed = False update.pushed = False self.db.commit() with mock.patch('bodhi.server.models.util.greenwave_api_post' ) as mock_greenwave: greenwave_response = { 'policies_satisfied': True, 'summary': "all tests have passed" } mock_greenwave.return_value = greenwave_response with fml_testing.mock_sends( update_schemas.UpdateReadyForTestingV1): self.handler(self.sample_side_tag_message) assert update.builds[0].signed is True assert update.builds[0].update.request is None assert update.status == UpdateStatus.testing assert update.pushed is True assert update.test_gating_status == TestGatingStatus.passed
def test_resume_empty_compose(self, publish): """ Test correct operation when the --resume flag is given but one of the Composes has no updates. """ cli = CliRunner() # Let's mark ejabberd as locked and already in a push. Since we are resuming and since we # will decline pushing the first time we are asked, it should be the only package that gets # included. ejabberd = self.create_update([u'ejabberd-16.09-4.fc17']) ejabberd.builds[0].signed = True ejabberd.locked = True compose = models.Compose(release=ejabberd.release, request=ejabberd.request) self.db.add(compose) # This compose has no updates, so bodhi-push should delete it. compose = models.Compose(release=ejabberd.release, request=models.UpdateRequest.stable) self.db.add(compose) self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): result = cli.invoke(push.push, ['--username', 'bowlofeggs', '--resume'], input='y\ny') self.assertEqual(result.exit_code, 0) self.assertEqual(result.output, TEST_RESUME_EMPTY_COMPOSE) ejabberd = self.db.query( models.Update).filter_by(title=u'ejabberd-16.09-4.fc17').one() python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() publish.assert_called_once_with( topic='masher.start', msg={ 'composes': [ejabberd.compose.__json__(composer=True)], 'resume': True, 'agent': 'bowlofeggs', 'api_version': 2 }, force=True) # ejabberd should still be locked. self.assertTrue(ejabberd.locked) self.assertTrue(ejabberd.date_locked <= datetime.utcnow()) self.assertEqual(ejabberd.compose.release, ejabberd.release) self.assertEqual(ejabberd.compose.request, ejabberd.request) # These should be left alone. for u in [python_nose, python_paste_deploy]: self.assertFalse(u.locked) self.assertIsNone(u.date_locked) self.assertIsNone(u.compose) # The empty compose should have been deleted. self.assertEqual( self.db.query(models.Compose).filter_by( release_id=ejabberd.release.id, request=models.UpdateRequest.stable).count(), 0)
def test_edited_update_bugs_in_update(self, work_on_bugs, fetch_test_cases, sleep): """ Test with a message that indicates that the update is being edited, and the list of bugs matches what UpdatesHandler finds in the database. """ h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) update = models.Build.query.filter_by( nvr='bodhi-2.0-1.fc17').one().update message = Message(topic='bodhi.update.edit', body={ 'msg': { 'update': { 'alias': update.alias }, 'new_bugs': ['12345'] } }) h(message) self.assertEqual(work_on_bugs.call_count, 1) self.assertTrue( isinstance(work_on_bugs.mock_calls[0][1][1], sqlalchemy.orm.session.Session)) self.assertEqual(work_on_bugs.mock_calls[0][1][2].title, u'bodhi-2.0-1.fc17') self.assertEqual([b.bug_id for b in work_on_bugs.mock_calls[0][1][3]], [12345]) self.assertEqual(fetch_test_cases.call_count, 1) self.assertTrue( isinstance(fetch_test_cases.mock_calls[0][1][1], sqlalchemy.orm.session.Session)) sleep.assert_called_once_with(1)
def test_request_testing(self, work_on_bugs, fetch_test_cases): """ Assert correct behavior when the message tells us that the update is requested for testing. """ hub = mock.MagicMock() hub.config = {'environment': 'environment', 'topic_prefix': 'topic_prefix'} h = updates.UpdatesHandler(hub) h.db_factory = base.TransactionalSessionMaker(self.Session) # Throw a bogus bug id in there to ensure it doesn't raise AssertionError. message = { 'topic': 'bodhi.update.request.testing', 'body': {'msg': {'update': {'alias': u'bodhi-2.0-1.fc17'}, 'new_bugs': ['this isnt a real bug lol']}}} h.consume(message) self.assertEqual(work_on_bugs.call_count, 1) self.assertTrue(isinstance(work_on_bugs.mock_calls[0][1][1], sqlalchemy.orm.session.Session)) self.assertEqual(work_on_bugs.mock_calls[0][1][2].title, u'bodhi-2.0-1.fc17') # Despite our weird bogus bug id, the update's bug list should have been used. self.assertEqual([b.bug_id for b in work_on_bugs.mock_calls[0][1][3]], [12345]) self.assertEqual(fetch_test_cases.call_count, 1) self.assertTrue(isinstance(fetch_test_cases.mock_calls[0][1][1], sqlalchemy.orm.session.Session))
def test_update_not_found(self, work_on_bugs, fetch_test_cases): """ If the message references an update that isn't found, assert that an Exception is raised. """ hub = mock.MagicMock() hub.config = { 'environment': 'environment', 'topic_prefix': 'topic_prefix' } h = updates.UpdatesHandler(hub) h.db_factory = base.TransactionalSessionMaker(self.Session) # Use a bogus topic to trigger the NotImplementedError. message = { 'topic': 'bodhi.update.request.testing', 'body': { 'msg': { 'update': { 'alias': u'hurd-1.0-1.fc26' } } } } with self.assertRaises(exceptions.BodhiException) as exc: h.consume(message) self.assertEqual(str(exc.exception), "Couldn't find alias u'hurd-1.0-1.fc26' in DB") self.assertEqual(work_on_bugs.call_count, 0) self.assertEqual(fetch_test_cases.call_count, 0)
def test_without_alias(self, work_on_bugs, fetch_test_cases, error): """ An error should get logged and the function should return if the message has no alias. """ hub = mock.MagicMock() hub.config = { 'environment': 'environment', 'topic_prefix': 'topic_prefix' } h = updates.UpdatesHandler(hub) h.db_factory = base.TransactionalSessionMaker(self.Session) message = { 'topic': 'bodhi.update.edit', 'body': { 'msg': { 'update': {}, 'new_bugs': ['12345'] } } } h.consume(message) self.assertEqual(work_on_bugs.call_count, 0) self.assertEqual(fetch_test_cases.call_count, 0) error.assert_called_once_with( "Update Handler got update with no alias {'new_bugs': ['12345'], 'update': {}}." )
def test_edited_update_bug_not_in_update(self, work_on_bugs, fetch_test_cases, sleep): """ Test with a message that indicates that the update is being edited, and the list of bugs contains one that UpdatesHandler does not find in the update. """ bug = models.Bug(bug_id=123456) self.db.add(bug) self.db.commit() h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) update = models.Build.query.filter_by(nvr='bodhi-2.0-1.fc17').one().update message = Message( topic='bodhi.update.edit', body={'msg': {'update': {'alias': update.alias}, 'new_bugs': ['12345', '123456']}} ) h(message) self.assertEqual(work_on_bugs.call_count, 1) self.assertTrue(isinstance(work_on_bugs.mock_calls[0][1][0], sqlalchemy.orm.session.Session)) self.assertEqual(work_on_bugs.mock_calls[0][1][1].title, 'bodhi-2.0-1.fc17') self.assertEqual([b.bug_id for b in work_on_bugs.mock_calls[0][1][2]], [12345, 123456]) self.assertEqual(fetch_test_cases.call_count, 1) self.assertTrue(isinstance(fetch_test_cases.mock_calls[0][1][0], sqlalchemy.orm.session.Session)) sleep.assert_called_once_with(1) # Bug with id '123456' should be attached to update bug = models.Bug.query.filter_by(bug_id=123456).one() update = models.Build.query.filter_by(nvr='bodhi-2.0-1.fc17').one().update self.assertIn(bug, update.bugs)
def test_unknown_topic(self, work_on_bugs, fetch_test_cases): """ Assert that NotImplementedError gets raised when an unknown topic is received. """ hub = mock.MagicMock() hub.config = { 'environment': 'environment', 'topic_prefix': 'topic_prefix' } h = updates.UpdatesHandler(hub) h.db_factory = base.TransactionalSessionMaker(self.Session) # Use a bogus topic to trigger the NotImplementedError. message = { 'topic': 'bodhi.update.nawjustkiddin', 'body': { 'msg': { 'update': { 'alias': u'bodhi-2.0-1.fc17' }, 'new_bugs': ['12345'] } } } self.assertRaises(NotImplementedError, h.consume, message) self.assertEqual(work_on_bugs.call_count, 0) self.assertEqual(fetch_test_cases.call_count, 0)
def test_request_testing(self, work_on_bugs, fetch_test_cases, sleep): """ Assert correct behavior when the message tells us that the update is requested for testing. """ h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) update = models.Build.query.filter_by(nvr='bodhi-2.0-1.fc17').one().update # Throw a bogus bug id in there to ensure it doesn't raise AssertionError. message = Message( topic='bodhi.update.request.testing', body={'msg': {'update': {'alias': update.alias}, 'new_bugs': ['this isnt a real bug lol']}} ) h(message) self.assertEqual(work_on_bugs.call_count, 1) self.assertTrue(isinstance(work_on_bugs.mock_calls[0][1][1], sqlalchemy.orm.session.Session)) self.assertEqual(work_on_bugs.mock_calls[0][1][2].title, 'bodhi-2.0-1.fc17') # Despite our weird bogus bug id, the update's bug list should have been used. self.assertEqual([b.bug_id for b in work_on_bugs.mock_calls[0][1][3]], [12345]) self.assertEqual(fetch_test_cases.call_count, 1) self.assertTrue(isinstance(fetch_test_cases.mock_calls[0][1][1], sqlalchemy.orm.session.Session)) sleep.assert_called_once_with(1)
def test_gating_required_true(self, sleep): """Assert that test_gating_status is updated when test_gating is enabled.""" update = models.Build.query.filter_by(nvr='bodhi-2.0-1.fc17').one().update update.test_gating_status = None h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) # Throw a bogus bug id in there to ensure it doesn't raise AssertionError. message = Message( topic='bodhi.update.request.testing', body={'msg': {'update': {'alias': update.alias}, 'new_bugs': []}} ) with mock.patch('bodhi.server.models.util.greenwave_api_post') as mock_greenwave: greenwave_response = { 'policies_satisfied': False, 'summary': 'what have you done‽', 'applicable_policies': ['taskotron_release_critical_tasks'], 'unsatisfied_requirements': [ {'testcase': 'dist.rpmdeplint', 'item': {'item': 'bodhi-2.0-1.fc17', 'type': 'koji_build'}, 'type': 'test-result-missing', 'scenario': None}, {'testcase': 'dist.rpmdeplint', 'item': {'original_spec_nvr': 'bodhi-2.0-1.fc17'}, 'type': 'test-result-missing', 'scenario': None}, {'testcase': 'dist.rpmdeplint', 'item': {'item': update.alias, 'type': 'bodhi_update'}, 'type': 'test-result-missing', 'scenario': None}]} mock_greenwave.return_value = greenwave_response h(message) update = models.Build.query.filter_by(nvr='bodhi-2.0-1.fc17').one().update self.assertEqual(update.test_gating_status, models.TestGatingStatus.failed) sleep.assert_called_once_with(1)
def test_unsigned_updates_skipped(self, publish, mock_init): """ Unsigned updates should get skipped. """ cli = CliRunner() # Let's mark nose unsigned so it gets skipped. python_nose = self.db.query(models.Update).filter_by( title=u'python-nose-1.3.7-11.fc17').one() python_nose.builds[0].signed = False self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker(self.Session)): result = cli.invoke(push.push, ['--username', 'bowlofeggs'], input='y') mock_init.assert_called_once_with(active=True, cert_prefix=u'shell') self.assertEqual(result.exit_code, 0) self.assertEqual(result.output, TEST_UNSIGNED_UPDATES_SKIPPED_EXPECTED_OUTPUT) python_nose = self.db.query(models.Update).filter_by( title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() publish.assert_called_once_with( topic='masher.start', msg={'composes': [python_paste_deploy.compose.__json__()], 'resume': False, 'agent': 'bowlofeggs', 'api_version': 2}, force=True) self.assertFalse(python_nose.locked) self.assertIsNone(python_nose.date_locked) self.assertTrue(python_paste_deploy.locked) self.assertTrue(python_paste_deploy.date_locked <= datetime.utcnow()) self.assertEqual(python_paste_deploy.compose.release, python_paste_deploy.release) self.assertEqual(python_paste_deploy.compose.request, python_paste_deploy.request)
def test_update_not_found(self, work_on_bugs, fetch_test_cases, sleep): """ If the message references an update that isn't found, assert that an Exception is raised. """ h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) with pytest.raises(exceptions.BodhiException) as exc: h.run(api_version=1, data={ 'action': 'testing', 'update': { 'alias': 'does not exist', 'builds': [{ 'nvr': 'bodhi-2.0-1.fc17' }], 'user': { 'name': 'brodhi' }, 'status': 'pending', 'request': 'testing' } }) assert str(exc.value) == "Couldn't find alias 'does not exist' in DB" assert work_on_bugs.call_count == 0 assert fetch_test_cases.call_count == 0 sleep.assert_called_once_with(1)
def test_cert_prefix_flag(self, publish, init): """ Test correct operation when the --cert-prefix flag is used. """ cli = CliRunner() self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): result = cli.invoke( push.push, ['--username', 'bowlofeggs', '--cert-prefix', 'some_prefix'], input='y') self.assertEqual(result.exit_code, 0) self.assertEqual(result.output, TEST_CERT_PREFIX_FLAG_EXPECTED_OUTPUT) init.assert_called_once_with(active=True, cert_prefix='some_prefix') publish.assert_called_once_with(topic='masher.start', msg={ 'composes': [{ 'security': False, 'release_id': 1, 'request': u'testing', 'content_type': u'rpm' }], 'resume': False, 'agent': 'bowlofeggs', 'api_version': 2 }, force=True)
def test_request_testing(self, work_on_bugs, fetch_test_cases, sleep): """ Assert correct behavior when the message tells us that the update is requested for testing. """ h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) update = models.Build.query.filter_by( nvr='bodhi-2.0-1.fc17').one().update h.run(api_version=1, data={ 'action': 'testing', 'update': { 'alias': update.alias, 'builds': [{ 'nvr': 'bodhi-2.0-1.fc17' }], 'user': { 'name': 'brodhi' }, 'status': str(update.status), 'request': str(update.request) } }) assert work_on_bugs.call_count == 1 assert isinstance(work_on_bugs.mock_calls[0][1][1], sqlalchemy.orm.session.Session) assert work_on_bugs.mock_calls[0][1][2].title == 'bodhi-2.0-1.fc17' # The update's bug list should have been used. assert [b.bug_id for b in work_on_bugs.mock_calls[0][1][3]] == [12345] assert fetch_test_cases.call_count == 1 assert isinstance(fetch_test_cases.mock_calls[0][1][1], sqlalchemy.orm.session.Session) sleep.assert_called_once_with(1)
def test_consume_from_tag_composed_by_bodhi(self, add_tag): """ Assert that update created from tag for a release composed by bodhi is handled correctly when message is received. The update request should be set to 'testing' so that the next composer run will change the update status. """ self.handler.db_factory = base.TransactionalSessionMaker(self.Session) update = self.db.query(Update).filter( Build.nvr == 'bodhi-2.0-1.fc17').one() update.from_tag = "f30-side-tag" update.status = UpdateStatus.pending update.request = None update.release.composed_by_bodhi = True update.release.pending_testing_tag = "f30-testing-pending" update.builds[0].signed = False update.pushed = False self.db.commit() with mock.patch('bodhi.server.models.util.greenwave_api_post' ) as mock_greenwave: greenwave_response = { 'policies_satisfied': True, 'summary': "all tests have passed" } mock_greenwave.return_value = greenwave_response with fml_testing.mock_sends(update_schemas.UpdateRequestTestingV1): self.handler(self.sample_side_tag_message_2) assert update.builds[0].signed is True assert update.builds[0].update.request == UpdateRequest.testing assert update.status == UpdateStatus.pending assert update.pushed is False assert update.test_gating_status == TestGatingStatus.passed assert add_tag.not_called()
def setup_method(self, method): """Set up environment for each test.""" super().setup_method(method) self.release = self.db.query(Release).filter_by(name='F17').first() if self.release: self.release.create_automatic_updates = True self.db.flush() else: self.release = self.create_release('17', create_automatic_updates=True) body = { 'build_id': 442562, 'name': 'colord', 'tag_id': 214, 'instance': 's390', 'tag': 'f17-updates-candidate', 'user': '******', 'version': '1.3.4', 'owner': 'sharkcz', 'release': '1.fc26', } self.sample_message = Message(topic='', body=body) self.sample_nvr = f"{body['name']}-{body['version']}-{body['release']}" self.db_factory = base.TransactionalSessionMaker(self.Session) self.handler = AutomaticUpdateHandler(self.db_factory)
def test_abort_push(self, publish): """ Ensure that the push gets aborted if the user types 'n' when asked if they want to push. """ cli = CliRunner() self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker(self.Session)): result = cli.invoke(push.push, ['--username', 'bowlofeggs'], input='n') # The exit code is 1 when the push is aborted. self.assertEqual(result.exit_code, 1) # This is a terribly dirty hack that strips an SQLAlchemy warning about calling configure # on a scoped session with existing sessions. This should ultimately be fixed by making # sure there are no sessions when the CLI is invoked (since it calls configure) if 'scoped session' in result.output: doctored_output = result.output.split('\n', 2)[2] else: doctored_output = result.output self.assertEqual(doctored_output, TEST_ABORT_PUSH_EXPECTED_OUTPUT) self.assertEqual(publish.call_count, 0) # The updates should not be locked for u in [u'bodhi-2.0-1.fc17', u'python-nose-1.3.7-11.fc17', u'python-paste-deploy-1.5.2-8.fc17']: u = self.db.query(models.Update).filter_by(title=u).one() self.assertFalse(u.locked) self.assertIsNone(u.date_locked)
def test_no_updates_to_push(self, publish): """ If there are no updates to push, no push message should get sent. """ cli = CliRunner() python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() python_nose.builds[0].signed = False python_paste_deploy.builds[0].signed = False self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): result = cli.invoke(push.push, ['--username', 'bowlofeggs'], input='y') self.assertEqual(result.exit_code, 0) self.assertEqual(result.output, TEST_NO_UPDATES_TO_PUSH_EXPECTED_OUTPUT) self.assertEqual(publish.call_count, 0) # The updates should not be locked python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() for u in [python_nose, python_paste_deploy]: self.assertFalse(u.locked) self.assertIsNone(u.date_locked)
def test_cert_prefix_flag(self, publish, init): """ Test correct operation when the --cert-prefix flag is used. """ cli = CliRunner() self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): result = cli.invoke( push.push, ['--username', 'bowlofeggs', '--cert-prefix', 'some_prefix'], input='y') self.assertEqual(result.exit_code, 0) self.assertEqual(result.output, TEST_CERT_PREFIX_FLAG_EXPECTED_OUTPUT) init.assert_called_once_with(active=True, cert_prefix='some_prefix') publish.assert_called_once_with( topic='masher.start', msg={ 'updates': [ 'python-nose-1.3.7-11.fc17', u'python-paste-deploy-1.5.2-8.fc17' ], 'resume': False, 'agent': 'bowlofeggs' }, force=True)
def test_not_rawhide_update_signed_stays_pending(self, work_on_bugs, fetch_test_cases, sleep): """ Assert that a non rawhide pending update that was edited does not get moved to testing if all the builds in the update are signed. """ update = models.Build.query.filter_by( nvr='bodhi-2.0-1.fc17').one().update update.status = models.UpdateStatus.pending update.release.composed_by_bodhi = True update.builds[0].signed = True h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) h.run(api_version=1, data={ 'action': 'edit', 'update': { 'alias': update.alias, 'builds': [{ 'nvr': 'bodhi-2.0-1.fc17' }], 'user': { 'name': 'bodhi' }, 'status': str(update.status), 'request': str(update.request) }, 'new_bugs': [] }) assert update.status == models.UpdateStatus.pending
def test_resume_human_says_no(self, publish): """ Test correct operation when the --resume flag is given but the human says they don't want to resume one of the lockfiles. """ cli = CliRunner() # Let's mark ejabberd as locked and already in a push. Since we are resuming and since we # will decline pushing the first time we are asked, it should be the only package that gets # included. ejabberd = self.create_update([u'ejabberd-16.09-4.fc17']) ejabberd.builds[0].signed = True ejabberd.locked = True compose = models.Compose(release=ejabberd.release, request=ejabberd.request) self.db.add(compose) python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_nose.locked = True python_nose.request = models.UpdateRequest.stable compose = models.Compose(release=python_nose.release, request=python_nose.request) self.db.add(compose) self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): result = cli.invoke(push.push, ['--username', 'bowlofeggs', '--resume'], input='y\nn\ny') self.assertEqual(result.exit_code, 0) self.assertEqual(result.output, TEST_RESUME_HUMAN_SAYS_NO_EXPECTED_OUTPUT) ejabberd = self.db.query( models.Update).filter_by(title=u'ejabberd-16.09-4.fc17').one() python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() publish.assert_called_once_with( topic='masher.start', msg={ 'composes': [ejabberd.compose.__json__(composer=True)], 'resume': True, 'agent': 'bowlofeggs', 'api_version': 2 }, force=True) # These should still be locked. for u in [ejabberd, python_nose]: self.assertTrue(u.locked) self.assertTrue(u.date_locked <= datetime.utcnow()) self.assertEqual(u.compose.release, u.release) self.assertEqual(u.compose.request, u.request) # paste_deploy should have been left alone self.assertFalse(python_paste_deploy.locked) self.assertIsNone(python_paste_deploy.date_locked) self.assertIsNone(python_paste_deploy.compose)
def test_gating_required_true(self, sleep): """Assert that test_gating_status is updated when test_gating is enabled.""" update = models.Build.query.filter_by( nvr='bodhi-2.0-1.fc17').one().update update.test_gating_status = None h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) with mock.patch('bodhi.server.models.util.greenwave_api_post' ) as mock_greenwave: greenwave_response = { 'policies_satisfied': False, 'summary': 'what have you done‽', 'applicable_policies': ['taskotron_release_critical_tasks'], 'unsatisfied_requirements': [{ 'testcase': 'dist.rpmdeplint', 'item': { 'item': 'bodhi-2.0-1.fc17', 'type': 'koji_build' }, 'type': 'test-result-missing', 'scenario': None }, { 'testcase': 'dist.rpmdeplint', 'item': { 'item': update.alias, 'type': 'bodhi_update' }, 'type': 'test-result-missing', 'scenario': None }] } mock_greenwave.return_value = greenwave_response h.run(api_version=1, data={ 'action': 'testing', 'update': { 'alias': update.alias, 'builds': [{ 'nvr': 'bodhi-2.0-1.fc17' }], 'user': { 'name': 'brodhi' }, 'status': str(update.status), 'request': str(update.request) }, 'new_bugs': [] }) update = models.Build.query.filter_by( nvr='bodhi-2.0-1.fc17').one().update self.assertEqual(update.test_gating_status, models.TestGatingStatus.failed) sleep.assert_called_once_with(1)
def test_unknown_api_version(self, log_error, work_on_bugs, fetch_test_cases): """Test an unknown API version""" h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) h.run(api_version="unknown", data={}) work_on_bugs.assert_not_called() fetch_test_cases.assert_not_called() log_error.assert_called_with( "The Updates Handler doesn't know how to handle api_version unknown. " "Message was: {}")
def test_resume_flag(self, publish, mock_init): """ Test correct operation when the --resume flag is given. """ cli = CliRunner() # Let's mark ejabberd as locked and already in a push. Since we are resuming, it should be # the only package that gets included. ejabberd = self.create_update([u'ejabberd-16.09-4.fc17']) ejabberd.builds[0].signed = True ejabberd.locked = True compose = models.Compose(release=ejabberd.release, request=ejabberd.request) self.db.add(compose) self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): result = cli.invoke(push.push, ['--username', 'bowlofeggs', '--resume'], input='y\ny') self.assertEqual(result.exit_code, 0) mock_init.assert_called_once_with(active=True, cert_prefix=u'shell') self.assertEqual(result.output, TEST_RESUME_FLAG_EXPECTED_OUTPUT) ejabberd = self.db.query( models.Update).filter_by(title=u'ejabberd-16.09-4.fc17').one() python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() publish.assert_called_once_with(topic='masher.start', msg={ 'composes': [ejabberd.compose.__json__()], 'resume': True, 'agent': 'bowlofeggs', 'api_version': 2 }, force=True) # ejabberd should be locked still self.assertTrue(ejabberd.locked) self.assertTrue(ejabberd.date_locked <= datetime.utcnow()) self.assertEqual(ejabberd.compose.release, ejabberd.release) self.assertEqual(ejabberd.compose.request, ejabberd.request) # The other packages should have been left alone for u in [python_nose, python_paste_deploy]: self.assertFalse(u.locked) self.assertIsNone(u.date_locked) self.assertIsNone(u.compose)
def test_locked_updates(self, publish, mock_init): """ Test correct operation when there are some locked updates. """ cli = CliRunner() # Let's mark ejabberd as locked and already in a push. bodhi-push should prompt the user to # resume this compose rather than starting a new one. ejabberd = self.create_update([u'ejabberd-16.09-4.fc17']) ejabberd.builds[0].signed = True ejabberd.locked = True compose = models.Compose(release=ejabberd.release, request=ejabberd.request, state=models.ComposeState.failed, error_message=u'y r u so mean nfs') self.db.add(compose) self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): result = cli.invoke(push.push, ['--username', 'bowlofeggs'], input='y\ny') self.assertEqual(result.exit_code, 0) mock_init.assert_called_once_with(active=True, cert_prefix=u'shell') self.assertEqual(result.output, TEST_LOCKED_UPDATES_EXPECTED_OUTPUT) publish.assert_called_once_with(topic='masher.start', msg={ 'composes': [ejabberd.compose.__json__()], 'resume': True, 'agent': 'bowlofeggs', 'api_version': 2 }, force=True) ejabberd = self.db.query( models.Update).filter_by(title=u'ejabberd-16.09-4.fc17').one() self.assertTrue(ejabberd.locked) self.assertTrue(ejabberd.date_locked <= datetime.utcnow()) self.assertEqual(ejabberd.compose.release, ejabberd.release) self.assertEqual(ejabberd.compose.request, ejabberd.request) self.assertEqual(ejabberd.compose.state, models.ComposeState.requested) self.assertEqual(ejabberd.compose.error_message, '') python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() for u in [python_nose, python_paste_deploy]: self.assertFalse(u.locked) self.assertIsNone(u.date_locked)
def test_edited_update_bug_not_in_update(self, work_on_bugs, fetch_test_cases, sleep): """ Test an update edition when the list of bugs contains one that UpdatesHandler does not find in the update. """ bug = models.Bug(bug_id=123456) self.db.add(bug) self.db.commit() h = updates.UpdatesHandler() h.db_factory = base.TransactionalSessionMaker(self.Session) update = models.Build.query.filter_by( nvr='bodhi-2.0-1.fc17').one().update h.run(api_version=1, data={ 'action': 'edit', 'update': { 'alias': update.alias, 'builds': [{ 'nvr': 'bodhi-2.0-1.fc17' }], 'user': { 'name': 'brodhi' }, 'status': str(update.status), 'request': str(update.request) }, 'new_bugs': [12345, 123456] }) self.assertEqual(work_on_bugs.call_count, 1) self.assertTrue( isinstance(work_on_bugs.mock_calls[0][1][0], sqlalchemy.orm.session.Session)) self.assertEqual(work_on_bugs.mock_calls[0][1][1].title, 'bodhi-2.0-1.fc17') self.assertEqual([b.bug_id for b in work_on_bugs.mock_calls[0][1][2]], [12345, 123456]) self.assertEqual(fetch_test_cases.call_count, 1) self.assertTrue( isinstance(fetch_test_cases.mock_calls[0][1][0], sqlalchemy.orm.session.Session)) sleep.assert_called_once_with(1) # Bug with id '123456' should be attached to update bug = models.Bug.query.filter_by(bug_id=123456).one() update = models.Build.query.filter_by( nvr='bodhi-2.0-1.fc17').one().update self.assertIn(bug, update.bugs)
def test_unsigned_updates_signed_updated(self, publish, mock_init): """ Unsigned updates should get marked signed. """ cli = CliRunner() # Let's mark nose unsigned so it gets marked signed. python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_nose.builds[0].signed = False self.db.commit() with mock.patch('bodhi.server.push.transactional_session_maker', return_value=base.TransactionalSessionMaker( self.Session)): # Note: this is NOT the signing-pending tag with mock.patch('bodhi.server.buildsys.DevBuildsys.listTags', return_value=[{ 'name': 'f17-updates-testing' }]): result = cli.invoke(push.push, ['--username', 'bowlofeggs'], input='y') self.assertEqual(result.exception, None) mock_init.assert_called_once_with(active=True, cert_prefix=u'shell') self.assertEqual(result.exit_code, 0) python_nose = self.db.query( models.Update).filter_by(title=u'python-nose-1.3.7-11.fc17').one() python_paste_deploy = self.db.query(models.Update).filter_by( title=u'python-paste-deploy-1.5.2-8.fc17').one() publish.assert_called_once_with( topic='masher.start', msg={ 'composes': [python_paste_deploy.compose.__json__(composer=True)], 'resume': False, 'agent': 'bowlofeggs', 'api_version': 2 }, force=True) self.assertTrue(python_nose.locked) self.assertTrue(python_nose.date_locked <= datetime.utcnow()) self.assertEqual(python_nose.compose.release, python_paste_deploy.release) self.assertEqual(python_nose.compose.request, python_paste_deploy.request) self.assertTrue(python_paste_deploy.locked) self.assertTrue(python_paste_deploy.date_locked <= datetime.utcnow()) self.assertEqual(python_paste_deploy.compose.release, python_paste_deploy.release) self.assertEqual(python_paste_deploy.compose.request, python_paste_deploy.request)