diff --git a/module_build_service/resolver/DBResolver.py b/module_build_service/resolver/DBResolver.py index acf53c94..02bfab0e 100644 --- a/module_build_service/resolver/DBResolver.py +++ b/module_build_service/resolver/DBResolver.py @@ -40,6 +40,15 @@ class DBResolver(GenericResolver): def __init__(self, config): self.config = config + def _get_module(self, name, stream, version, context, strict=False): + with models.make_session(self.config) as session: + mb = models.ModuleBuild.get_build_from_nsvc( + session, name, stream, version, context) + if mb is None and strict: + raise UnprocessableEntity( + 'Cannot find any module builds for %s:%s' % (name, stream)) + return mb.extended_json() + def get_module_modulemds(self, name, stream, version=None, context=None, strict=False, stream_version_lte=False): """ @@ -57,11 +66,12 @@ class DBResolver(GenericResolver): less than or equal the stream version computed from `stream`. :return: List of Modulemd metadata instances matching the query """ + if version and context: + mmd = self._get_module(name, stream, version, context, strict=strict) + return [self.extract_modulemd(mmd['modulemd'])] + with models.make_session(self.config) as session: - if version and context: - builds = [models.ModuleBuild.get_build_from_nsvc( - session, name, stream, version, context)] - elif not version and not context: + if not version and not context: if (stream_version_lte and len(str(models.ModuleBuild.get_stream_version( stream, right_pad=False))) >= 5): stream_version = models.ModuleBuild.get_stream_version(stream) diff --git a/module_build_service/resolver/base.py b/module_build_service/resolver/base.py index d2752636..a6c19c15 100644 --- a/module_build_service/resolver/base.py +++ b/module_build_service/resolver/base.py @@ -37,7 +37,14 @@ class GenericResolver(six.with_metaclass(ABCMeta)): """ _resolvers = cfg.SUPPORTED_RESOLVERS + + # Resolver name. Each subclass of GenericResolver must set its own name. backend = "generic" + + # Supported resolver backends registry. Generally, resolver backend is + # registered by calling :meth:`GenericResolver.register_backend_class`. + # This is a mapping from resolver name to backend class object + # For example, {'mbs': MBSResolver} backends = {} @classmethod @@ -46,13 +53,19 @@ class GenericResolver(six.with_metaclass(ABCMeta)): @classmethod def create(cls, config, backend=None, **extra): - """ - :param backend: a string representing resolver e.g. 'db' + """Factory method to create a resolver object - Any additional arguments are optional extras which can be passed along - and are implementation-dependent. + :param config: MBS config object. + :type config: :class:`Config` + :kwarg str backend: resolver backend name, e.g. 'db'. If omitted, + system configuration ``resolver`` is used. + :kwarg extra: any additional arguments are optional extras which can + be passed along and are implementation-dependent. + :return: resolver backend object. + :rtype: corresponding registered resolver class. + :raises ValueError: if specified resolver backend name is not + registered. """ - # get the appropriate resolver backend via configuration if not backend: backend = conf.resolver diff --git a/module_build_service/utils/submit.py b/module_build_service/utils/submit.py index 2720b319..f07a5d80 100644 --- a/module_build_service/utils/submit.py +++ b/module_build_service/utils/submit.py @@ -136,21 +136,27 @@ def _record_ursine_rpms(req_data): with a list of RPMs N-E:V-R which are built for the found stream collision modules. """ - from module_build_service.builder import GenericBuilder + from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder resolver = module_build_service.resolver.GenericResolver.create(conf) # Key stream_collision_modules is not used after rpms are recorded, but # just keep it here in case it would be helpful in the future. modules_nsvc = req_data['stream_collision_modules'] - get_built_rpms = GenericBuilder.backends[conf.system].get_built_rpms_in_module_build built_rpms = [] + koji_session = KojiModuleBuilder.get_session(conf, None) + for nsvc in modules_nsvc: name, stream, version, context = nsvc.split(':') - mmd = resolver.get_module_modulemds( - name, stream, version, context, True)[0] - built_rpms.extend(get_built_rpms(mmd)) + module = resolver._get_module(name, stream, version, context, strict=True) + rpms = koji_session.listTaggedRPMS(module['koji_tag'], latest=True)[0] + built_rpms.extend( + kobo.rpmlib.make_nvr(rpm, force_epoch=True) for rpm in rpms + ) + # In case there is duplicate NEVRs, ensure every NEVR is unique in the final list. + # And, sometimes, sorted list of RPMs would be easier to read. + built_rpms = sorted(set(built_rpms)) req_data['ursine_rpms'] = built_rpms diff --git a/tests/test_utils/test_utils.py b/tests/test_utils/test_utils.py index fb11652b..3c9bb8a7 100644 --- a/tests/test_utils/test_utils.py +++ b/tests/test_utils/test_utils.py @@ -1156,11 +1156,8 @@ class TestRecordFilteredRPMs: def teardown_method(self): clean_database() - # For simplicity, test just queries database. So, no need to code more for - # mocking remote MBS service. - @patch.object(module_build_service.conf, 'resolver', new='db') - @patch('module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session') - def test_generate_and_store_filtered_rpms(self, get_session): + @patch('koji.ClientSession') + def test_generate_and_store_filtered_rpms(self, ClientSession): def mocklistTaggedRPMs(tag, latest): # Result returned from listTaggedRPMs should contain two lists. @@ -1197,9 +1194,11 @@ class TestRecordFilteredRPMs: } return rpms[tag] - get_session.return_value.listTaggedRPMS.side_effect = mocklistTaggedRPMs + ClientSession.return_value.listTaggedRPMS.side_effect = mocklistTaggedRPMs + + with patch.object(conf, 'resolver', new='db'): + mmd = module_build_service.utils.submit.record_filtered_rpms(self.mmd) - mmd = module_build_service.utils.submit.record_filtered_rpms(self.mmd) xmd_mbs = mmd.get_xmd()['mbs'].unpack() assert ['pkg-1.0-1.fc28'] == xmd_mbs['buildrequires']['modulea']['filtered_rpms']