From 639eb15971205bf45fad13911f8eb4137b6d3959 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Jan 28 2018 09:24:57 +0000 Subject: Add MockedKoji class to replace almost all KojiService mocking in Freshmaker tests. --- diff --git a/tests/helpers.py b/tests/helpers.py index 77a6dda..a0f3f38 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -24,6 +24,10 @@ import string import time import uuid import unittest +import koji + +from mock import patch +from functools import wraps from freshmaker import events from freshmaker import db @@ -67,6 +71,177 @@ class ModelsTestCase(FreshmakerTestCase): db.session.commit() +class MockedKoji(object): + def __init__(self): + self._koji_service = None + + # {"tag_name": ["build1_nvr", "build2_nvr", ...], ...} + # The list of build NVRs is kept sorted. + self.tags = {} + # ["build_nvr": [{"rpm_nvr": nvr, ...}, ...], ...] + self.rpms = {} + + def add_tag(self, tag_name): + """ + Adds new tag to Mocked Koji. + """ + if tag_name in self.tags: + return + self.tags[tag_name] = [] + + def tag_build(self, tag_name, nvr): + """ + Tags the build `nvr` to tag `tag_name`. + """ + self.tags[tag_name].append(nvr) + self.tags[tag_name].sort() + + def add_build(self, nvr, tags=None): + """ + Adds build `nvr` to Mocked Koji. Tags the build into `tags`. If tags + are not defined, ["tag-candidate", "tag-pending", "tag-alpha-1.0-set"] + is used. If the tags do not exist in Mocked Koji, they are added + automatically. + """ + if not tags: + tags = ["tag-candidate", "tag-pending", "tag-alpha-1.0-set"] + + for tag in tags: + self.add_tag(tag) + self.tag_build(tag, nvr) + + def add_build_rpms(self, build_nvr, rpm_nvrs=None, arches=None): + """ + Adds list of RPMs defined as NVRs in `rpms_nvrs` list into build + defined by `build_nvr` NVR. + If `rpm_nvrs` is not defined, build_nvr is used as default NVR. + If `arches` is not defined, ["src", "ppc", "i686", "x86_64"] is used as + default list of arches. + """ + if build_nvr not in self.rpms: + self.rpms[build_nvr] = [] + + if not rpm_nvrs: + rpm_nvrs = [build_nvr] + + if not arches: + arches = ["src", "ppc", "i686", "x86_64"] + + for nvr in rpm_nvrs: + for arch in arches: + parsed_nvr = koji.parse_NVR(nvr) + self.rpms[build_nvr].append({ + 'arch': arch, + 'name': parsed_nvr["name"], + 'release': parsed_nvr["release"], + 'version': parsed_nvr["version"], + 'nvr': nvr, + }) + + def _get_build_rpms(self, build_nvr, arches=None): + """ + Mocks the KojiService.get_build_rpms. + """ + if not arches: + return self.rpms[build_nvr] + + return [rpm for rpm in self.rpms[build_nvr] if rpm["arch"] in arches] + + def _get_build_target(self, build_target): + """ + Mocks the KojiService.get_build_target. + """ + if build_target == "guest-rhel-7.4-docker": + return { + 'build_tag': 10052, + 'build_tag_name': 'guest-rhel-7.4-docker-build', + 'dest_tag': 10051, + 'dest_tag_name': 'guest-rhel-7.4-candidate', + 'id': 3205, + 'name': 'guest-rhel-7.4-docker' + } + return None + + def _session_list_tags(self, nvr): + """ + Mocks KojiService.session.listTags. + """ + ret = [] + for tag_name, nvrs in self.tags.items(): + if nvr in nvrs: + ret.append({ + "name": tag_name + }) + return ret + + def _session_list_tagged(self, tag, **kwargs): + """ + Mocks KojiService.session.listTagged. + """ + if "latest" in kwargs and kwargs["latest"]: + return_latest = True + else: + return_latest = False + + ret = [] + packages = [] + for nvr in self.tags[tag]: + package = koji.parse_NVR(nvr)["name"] + if return_latest and package in packages: + continue + + packages.append(package) + ret.append({ + 'nvr': nvr, + }) + + return ret + + def start(self): + """ + Starts the Koji mocking. + """ + self._mocked_koji_service_patch = patch( + 'freshmaker.kojiservice.KojiService') + self._koji_service = self._mocked_koji_service_patch.start().return_value + + self._koji_service.get_build_target.side_effect = self._get_build_target + self._koji_service.get_build_rpms.side_effect = self._get_build_rpms + + self._koji_session = self._koji_service.session + self._koji_session.listTags.side_effect = self._session_list_tags + self._koji_session.listTagged.side_effect = self._session_list_tagged + + return self + + def stop(self): + """ + Stops the Koji mocking. + """ + if self._koji_service: + self._mocked_koji_service_patch.stop() + self._koji_service = None + + def __enter__(self): + return self.start() + + def __exit__(self, *args): + self.stop() + + +def mock_koji(f): + """ + Wrapper which mocks the Koji. It adds MockedKoji instance as the last + *arg of original ufnction. + """ + @wraps(f) + def wrapped(*args, **kwargs): + with MockedKoji() as mocked_koji: + return f(*args + (mocked_koji, ), **kwargs) + + return wrapped + + class FedMsgFactory(object): def __init__(self, *args, **kwargs): self.msg_id = "%s-%s" % (time.strftime("%Y"), uuid.uuid4()) diff --git a/tests/test_bodhi_update_complete_stable_handler.py b/tests/test_bodhi_update_complete_stable_handler.py index 5e9db1b..bc52307 100644 --- a/tests/test_bodhi_update_complete_stable_handler.py +++ b/tests/test_bodhi_update_complete_stable_handler.py @@ -205,51 +205,20 @@ class BodhiUpdateCompleteStableHandlerTest(helpers.ModelsTestCase): found_containers = sorted(containers, key=lambda item: item['id']) self.assertEqual(expected_found_containers, found_containers) - @mock.patch('freshmaker.kojiservice.KojiService.get_build_rpms') - def test_get_rpms_included_in_bohdhi_update(self, get_build_rpms): - rpms = { - 'community-mysql-5.7.18-2.fc25': [ - { - 'id': 9515683, - 'name': 'community-mysql-devel', - 'nvr': 'community-mysql-devel-5.7.18-2.fc25', - 'release': '2.fc25', - 'version': '5.7.18', - }, - { - 'id': 9515682, - 'name': 'community-mysql-libs', - 'nvr': 'community-mysql-libs-5.7.18-2.fc25', - 'release': '2.fc25', - 'version': '5.7.18', - }, - { - 'id': 9515681, - 'name': 'community-mysql-server', - 'nvr': 'community-mysql-server-5.7.18-2.fc25', - 'release': '2.fc25', - 'version': '5.7.18', - }, - ], - 'qt5-qtwebengine-5.8.0-11.fc25': [ - { - 'id': 9571317, - 'name': 'qt5-qtwebengine-devel', - 'nvr': 'qt5-qtwebengine-devel-5.8.0-11.fc25', - 'release': '11.fc25', - 'version': '5.8.0', - }, - { - 'id': 9571316, - 'name': 'qt5-qtwebengine-examples', - 'nvr': 'qt5-qtwebengine-examples-5.8.0-11.fc25', - 'release': '11.fc25', - 'version': '5.8.0', - } - ], - } - - get_build_rpms.side_effect = lambda x: rpms[x] + @helpers.mock_koji + def test_get_rpms_included_in_bohdhi_update(self, mocked_koji): + mocked_koji.add_build("community-mysql-5.7.18-2.fc25") + mocked_koji.add_build_rpms( + "community-mysql-5.7.18-2.fc25", + ['community-mysql-devel-5.7.18-2.fc25', + 'community-mysql-libs-5.7.18-2.fc25', + 'community-mysql-server-5.7.18-2.fc25'], ["i686"]) + + mocked_koji.add_build("qt5-qtwebengine-5.8.0-11.fc25") + mocked_koji.add_build_rpms( + "qt5-qtwebengine-5.8.0-11.fc25", + ['qt5-qtwebengine-devel-5.8.0-11.fc25', + 'qt5-qtwebengine-examples-5.8.0-11.fc25'], ["i686"]) builds = [ { @@ -272,5 +241,5 @@ class BodhiUpdateCompleteStableHandlerTest(helpers.ModelsTestCase): self.assertEqual(5, len(rpms)) - rpm = list(filter(lambda item: item['id'] == 9515681, rpms)) + rpm = list(filter(lambda item: item['nvr'] == "community-mysql-server-5.7.18-2.fc25", rpms)) self.assertEqual(1, len(rpm)) diff --git a/tests/test_errata_advisory_rpms_signed_handler.py b/tests/test_errata_advisory_rpms_signed_handler.py index d11007d..972f0b2 100644 --- a/tests/test_errata_advisory_rpms_signed_handler.py +++ b/tests/test_errata_advisory_rpms_signed_handler.py @@ -430,29 +430,16 @@ class TestGetBaseImageBuildTag(helpers.FreshmakerTestCase): }) self.handler = ErrataAdvisoryRPMsSignedHandler() - @patch('freshmaker.kojiservice.KojiService') - def test_get_build_tag_name(self, KojiService): - koji_service = KojiService.return_value - koji_service.get_build_target.return_value = { - 'build_tag': 10052, - 'build_tag_name': 'guest-rhel-7.4-docker-build', - 'dest_tag': 10051, - 'dest_tag_name': 'guest-rhel-7.4-candidate', - 'id': 3205, - 'name': 'guest-rhel-7.4-docker' - } - + @helpers.mock_koji + def test_get_build_tag_name(self, mocked_koji): result = self.handler._get_base_image_build_tag( 'guest-rhel-7.4-docker') self.assertEqual('guest-rhel-7.4-docker-build', result) - @patch('freshmaker.kojiservice.KojiService') - def test_no_target_is_returned(self, KojiService): - koji_service = KojiService.return_value - koji_service.get_build_target.return_value = None - + @helpers.mock_koji + def test_no_target_is_returned(self, mocked_koji): result = self.handler._get_base_image_build_tag( - 'guest-rhel-7.4-docker') + 'guest-rhel-7.4-docker-unknown') self.assertIsNone(result) diff --git a/tests/test_errata_advisory_state_changed.py b/tests/test_errata_advisory_state_changed.py index 8119a7f..0b7a55c 100644 --- a/tests/test_errata_advisory_state_changed.py +++ b/tests/test_errata_advisory_state_changed.py @@ -41,38 +41,19 @@ from tests import helpers class TestFindBuildSrpmName(helpers.FreshmakerTestCase): """Test ErrataAdvisoryRPMsSignedHandler._find_build_srpm_name""" - @patch('koji.ClientSession') - def test_find_srpm_name(self, ClientSession): - session = ClientSession.return_value - session.getBuild.return_value = { - 'build_id': 439408, - 'id': 439408, - 'name': 'bind-dyndb-ldap', - 'nvr': 'bind-dyndb-ldap-2.3-8.el6', - } - session.listRPMs.return_value = [{ - 'arch': 'src', - 'name': 'bind-dyndb-ldap', - 'nvr': 'bind-dyndb-ldap-2.3-8.el6', - }] + @helpers.mock_koji + def test_find_srpm_name(self, mocked_koji): + mocked_koji.add_build("bind-dyndb-ldap-2.3-8.el6") + mocked_koji.add_build_rpms("bind-dyndb-ldap-2.3-8.el6") handler = ErrataAdvisoryRPMsSignedHandler() srpm_name = handler._find_build_srpm_name('bind-dyndb-ldap-2.3-8.el6') - - session.getBuild.assert_called_once_with('bind-dyndb-ldap-2.3-8.el6') - session.listRPMs.assert_called_once_with(buildID=439408, arches='src') self.assertEqual('bind-dyndb-ldap', srpm_name) - @patch('koji.ClientSession') - def test_error_if_no_srpm_in_build(self, ClientSession): - session = ClientSession.return_value - session.getBuild.return_value = { - 'build_id': 439408, - 'id': 439408, - 'name': 'bind-dyndb-ldap', - 'nvr': 'bind-dyndb-ldap-2.3-8.el6', - } - session.listRPMs.return_value = [] + @helpers.mock_koji + def test_error_if_no_srpm_in_build(self, mocked_koji): + mocked_koji.add_build("bind-dyndb-ldap-2.3-8.el6") + mocked_koji.add_build_rpms("bind-dyndb-ldap-2.3-8.el6", arches=["i686"]) handler = ErrataAdvisoryRPMsSignedHandler() @@ -83,9 +64,6 @@ class TestFindBuildSrpmName(helpers.FreshmakerTestCase): 'bind-dyndb-ldap-2.3-8.el6', ) - session.getBuild.assert_called_once_with('bind-dyndb-ldap-2.3-8.el6') - session.listRPMs.assert_called_once_with(buildID=439408, arches='src') - class TestAllowBuild(helpers.ModelsTestCase): """Test ErrataAdvisoryRPMsSignedHandler.allow_build""" @@ -422,41 +400,17 @@ class TestCheckImagesToRebuild(helpers.ModelsTestCase): class TestGetPackagesForCompose(helpers.FreshmakerTestCase): """Test ErrataAdvisoryRPMsSignedHandler._get_packages_for_compose""" - @patch('freshmaker.kojiservice.KojiService.get_build_rpms') - def test_get_packages(self, get_build_rpms): - get_build_rpms.return_value = [ - { - 'id': 4672404, - 'arch': 'src', - 'name': 'chkconfig', - 'release': '1.el7_3.1', - 'version': '1.7.2', - 'nvr': 'chkconfig-1.7.2-1.el7_3.1', - }, - { - 'id': 4672405, - 'arch': 'ppc', - 'name': 'chkconfig', - 'release': '1.el7_3.1', - 'version': '1.7.2', - 'nvr': 'chkconfig-1.7.2-1.el7_3.1', - }, - { - 'id': 4672420, - 'arch': 'i686', - 'name': 'chkconfig-debuginfo', - 'release': '1.el7_3.1', - 'version': '1.7.2', - 'nvr': 'chkconfig-debuginfo-1.7.2-1.el7_3.1', - } - ] - + @helpers.mock_koji + def test_get_packages(self, mocked_koji): build_nvr = 'chkconfig-1.7.2-1.el7_3.1' + mocked_koji.add_build(build_nvr) + mocked_koji.add_build_rpms( + build_nvr, + [build_nvr, "chkconfig-debuginfo-1.7.2-1.el7_3.1"]) + handler = ErrataAdvisoryRPMsSignedHandler() packages = handler._get_packages_for_compose(build_nvr) - get_build_rpms.assert_called_once_with(build_nvr) - self.assertEqual(set(['chkconfig', 'chkconfig-debuginfo']), set(packages)) @@ -464,113 +418,38 @@ class TestGetPackagesForCompose(helpers.FreshmakerTestCase): class TestGetComposeSource(helpers.FreshmakerTestCase): """Test ErrataAdvisoryRPMsSignedHandler._get_compose_source""" - @patch('freshmaker.kojiservice.KojiService.session', callable=PropertyMock) - def test_get_tag(self, session): - session.listTags.return_value = [ - { - 'id': 10974, - 'name': 'rhscl-3.0-rhel-6-candidate', - }, - { - 'id': 11030, - 'name': 'rhscl-3.0-rhel-6-pending', - }, - { - 'id': 11425, - 'name': 'rhscl-3.0-rhel-6-alpha-1.0-set', - } - ] - session.listTagged.return_value = [ - { - 'build_id': 568228, - 'nvr': 'rh-postgresql96-3.0-9.el6', - } - ] - + @helpers.mock_koji + def test_get_tag(self, mocked_koji): + mocked_koji.add_build("rh-postgresql96-3.0-9.el6") handler = ErrataAdvisoryRPMsSignedHandler() tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6') - self.assertEqual('rhscl-3.0-rhel-6-candidate', tag) - - @patch('freshmaker.kojiservice.KojiService.session', callable=PropertyMock) - def test_get_None_if_tag_has_new_build(self, session): - session.listTags.return_value = [ - { - 'id': 10974, - 'name': 'rhscl-3.0-rhel-6-candidate', - }, - { - 'id': 11030, - 'name': 'rhscl-3.0-rhel-6-pending', - }, - { - 'id': 11425, - 'name': 'rhscl-3.0-rhel-6-alpha-1.0-set', - } - ] - session.listTagged.return_value = [ - { - 'build_id': 568228, - 'nvr': 'rh-postgresql96-3.0-10.el6', - } - ] + self.assertEqual('tag-candidate', tag) + @helpers.mock_koji + def test_get_None_if_tag_has_new_build(self, mocked_koji): + mocked_koji.add_build("rh-postgresql96-3.0-9.el6") + mocked_koji.add_build("rh-postgresql96-3.0-10.el6") handler = ErrataAdvisoryRPMsSignedHandler() tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6') self.assertEqual(None, tag) - @patch('freshmaker.kojiservice.KojiService.session', callable=PropertyMock) - def test_get_tag_prefer_final_over_candidate(self, session): - session.listTags.return_value = [ - { - 'id': 10974, - 'name': 'rhel-6-candidate', - }, - { - 'id': 10975, - 'name': 'rhel-6', - }, - ] - session.listTagged.return_value = [ - { - 'build_id': 568228, - 'nvr': 'rh-postgresql96-3.0-9.el6', - } - ] - + @helpers.mock_koji + def test_get_tag_prefer_final_over_candidate(self, mocked_koji): + mocked_koji.add_build("rh-postgresql96-3.0-9.el6", + ["tag-candidate", "tag"]) handler = ErrataAdvisoryRPMsSignedHandler() tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6') - self.assertEqual('rhel-6', tag) - - @patch('freshmaker.kojiservice.KojiService.session', callable=PropertyMock) - def test_get_tag_fallback_to_second_tag(self, session): - session.listTags.return_value = [ - { - 'id': 10974, - 'name': 'rhel-6-candidate', - }, - { - 'id': 10975, - 'name': 'rhel-6', - }, - ] - session.listTagged.side_effect = [ - [ - { - 'build_id': 568228, - 'nvr': 'rh-postgresql96-3.0-10.el6', - } - ], - [ - { - 'build_id': 568228, - 'nvr': 'rh-postgresql96-3.0-9.el6', - } - ], - ] - + self.assertEqual('tag', tag) + + @helpers.mock_koji + def test_get_tag_fallback_to_second_tag(self, mocked_koji): + mocked_koji.add_build("rh-postgresql96-3.0-10.el6", + ["tag"]) + mocked_koji.add_build("rh-postgresql96-3.0-9.el6", + ["tag", "tag-candidate"]) handler = ErrataAdvisoryRPMsSignedHandler() tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6') - self.assertEqual('rhel-6-candidate', tag) + self.assertEqual('tag-candidate', tag) class TestPrepareYumRepo(helpers.ModelsTestCase):