From 8e7a43d5ff35cdefc57917a4865ea0b384522e5c Mon Sep 17 00:00:00 2001 From: mprahl Date: Mon, 23 Dec 2019 12:32:25 -0500 Subject: [PATCH] Move get_session and retry to separate modules to reduce circular imports --- .../builder/KojiContentGenerator.py | 18 +- .../builder/KojiModuleBuilder.py | 180 ++---------------- .../builder/MockModuleBuilder.py | 6 +- module_build_service/builder/base.py | 6 +- module_build_service/common/__init__.py | 0 module_build_service/common/koji.py | 162 ++++++++++++++++ module_build_service/common/retry.py | 31 +++ module_build_service/resolver/KojiResolver.py | 8 +- .../scheduler/default_modules.py | 10 +- .../scheduler/handlers/components.py | 4 +- .../scheduler/handlers/greenwave.py | 4 +- .../scheduler/handlers/modules.py | 5 +- module_build_service/scheduler/producer.py | 10 +- module_build_service/scm.py | 3 +- module_build_service/utils/general.py | 27 --- module_build_service/utils/ursine.py | 9 +- tests/test_build/test_build.py | 2 +- tests/test_builder/test_koji.py | 176 ++++++++--------- tests/test_common/__init__.py | 0 tests/test_common/test_koji.py | 13 ++ tests/test_resolver/test_koji.py | 2 +- tests/test_scheduler/test_default_modules.py | 8 +- tests/test_scheduler/test_repo_done.py | 8 +- tests/test_scheduler/test_tag_tagged.py | 12 +- 24 files changed, 350 insertions(+), 354 deletions(-) create mode 100644 module_build_service/common/__init__.py create mode 100644 module_build_service/common/koji.py create mode 100644 module_build_service/common/retry.py create mode 100644 tests/test_common/__init__.py create mode 100644 tests/test_common/test_koji.py diff --git a/module_build_service/builder/KojiContentGenerator.py b/module_build_service/builder/KojiContentGenerator.py index faea8ce2..0afc22a3 100644 --- a/module_build_service/builder/KojiContentGenerator.py +++ b/module_build_service/builder/KojiContentGenerator.py @@ -22,6 +22,7 @@ import koji import pungi.arch from module_build_service import conf, log, build_logs, Modulemd +from module_build_service.common.koji import get_session, koji_retrying_multicall_map from module_build_service.db_session import db_session from module_build_service.scm import SCM from module_build_service.utils import to_text_type, load_mmd, mmd_to_str @@ -29,12 +30,6 @@ from module_build_service.utils import to_text_type, load_mmd, mmd_to_str logging.basicConfig(level=logging.DEBUG) -def get_session(config, login=True): - from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder - - return KojiModuleBuilder.get_session(config, login=login) - - def strip_suffixes(s, suffixes): """ Helper function to remove suffixes from given string. @@ -54,17 +49,6 @@ def strip_suffixes(s, suffixes): return s -def koji_retrying_multicall_map(*args, **kwargs): - """ - Wrapper around KojiModuleBuilder.koji_retrying_multicall_map, because - we cannot import that method normally because of import loop. - """ - from module_build_service.builder.KojiModuleBuilder import ( - koji_retrying_multicall_map as multicall,) - - return multicall(*args, **kwargs) - - class KojiContentGenerator(object): """ Class for handling content generator imports of module builds into Koji """ diff --git a/module_build_service/builder/KojiModuleBuilder.py b/module_build_service/builder/KojiModuleBuilder.py index b017adc0..b74fe98d 100644 --- a/module_build_service/builder/KojiModuleBuilder.py +++ b/module_build_service/builder/KojiModuleBuilder.py @@ -13,8 +13,7 @@ import random import string import kobo.rpmlib import threading -import six.moves.xmlrpc_client as xmlrpclib -import munch + import locale from itertools import chain from OpenSSL.SSL import SysCallError @@ -24,114 +23,19 @@ from module_build_service import log, conf, models import module_build_service.scm import module_build_service.utils from module_build_service.builder.utils import execute_cmd +from module_build_service.common.retry import retry from module_build_service.db_session import db_session -from module_build_service.errors import ProgrammingError - from module_build_service.builder import GenericBuilder from module_build_service.builder.KojiContentGenerator import KojiContentGenerator +from module_build_service.common.koji import ( + get_session, koji_multicall_map, koji_retrying_multicall_map, +) from module_build_service.scheduler import events from module_build_service.utils import get_reusable_components, get_reusable_module, set_locale logging.basicConfig(level=logging.DEBUG) -def koji_multicall_map(koji_session, koji_session_fnc, list_of_args=None, list_of_kwargs=None): - """ - Calls the `koji_session_fnc` using Koji multicall feature N times based on the list of - arguments passed in `list_of_args` and `list_of_kwargs`. - Returns list of responses sorted the same way as input args/kwargs. In case of error, - the error message is logged and None is returned. - - For example to get the package ids of "httpd" and "apr" packages: - ids = koji_multicall_map(session, session.getPackageID, ["httpd", "apr"]) - # ids is now [280, 632] - - :param KojiSessions koji_session: KojiSession to use for multicall. - :param object koji_session_fnc: Python object representing the KojiSession method to call. - :param list list_of_args: List of args which are passed to each call of koji_session_fnc. - :param list list_of_kwargs: List of kwargs which are passed to each call of koji_session_fnc. - """ - if list_of_args is None and list_of_kwargs is None: - raise ProgrammingError("One of list_of_args or list_of_kwargs must be set.") - - if ( - type(list_of_args) not in [type(None), list] - or type(list_of_kwargs) not in [type(None), list] - ): - raise ProgrammingError("list_of_args and list_of_kwargs must be list or None.") - - if list_of_kwargs is None: - list_of_kwargs = [{}] * len(list_of_args) - if list_of_args is None: - list_of_args = [[]] * len(list_of_kwargs) - - if len(list_of_args) != len(list_of_kwargs): - raise ProgrammingError("Length of list_of_args and list_of_kwargs must be the same.") - - koji_session.multicall = True - for args, kwargs in zip(list_of_args, list_of_kwargs): - if type(args) != list: - args = [args] - if type(kwargs) != dict: - raise ProgrammingError("Every item in list_of_kwargs must be a dict") - koji_session_fnc(*args, **kwargs) - - try: - responses = koji_session.multiCall(strict=True) - except Exception: - log.exception( - "Exception raised for multicall of method %r with args %r, %r:", - koji_session_fnc, args, kwargs, - ) - return None - - if not responses: - log.error("Koji did not return response for multicall of %r", koji_session_fnc) - return None - if type(responses) != list: - log.error( - "Fault element was returned for multicall of method %r: %r", koji_session_fnc, responses - ) - return None - - results = [] - - # For the response specification, see - # https://web.archive.org/web/20060624230303/http://www.xmlrpc.com/discuss/msgReader$1208?mode=topic - # Relevant part of this: - # Multicall returns an array of responses. There will be one response for each call in - # the original array. The result will either be a one-item array containing the result value, - # or a struct of the form found inside the standard element. - for response, args, kwargs in zip(responses, list_of_args, list_of_kwargs): - if type(response) == list: - if not response: - log.error( - "Empty list returned for multicall of method %r with args %r, %r", - koji_session_fnc, args, kwargs - ) - return None - results.append(response[0]) - else: - log.error( - "Unexpected data returned for multicall of method %r with args %r, %r: %r", - koji_session_fnc, args, kwargs, response - ) - return None - - return results - - -@module_build_service.utils.retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError)) -def koji_retrying_multicall_map(*args, **kwargs): - """ - Retrying version of koji_multicall_map. This tries to retry the Koji call - in case of koji.GenericError or xmlrpclib.ProtocolError. - - Please refer to koji_multicall_map for further specification of arguments. - """ - return koji_multicall_map(*args, **kwargs) - - class KojiModuleBuilder(GenericBuilder): """ Koji specific builder class """ @@ -159,7 +63,7 @@ class KojiModuleBuilder(GenericBuilder): log.debug("Using koji profile %r" % config.koji_profile) log.debug("Using koji_config: %s" % config.koji_config) - self.koji_session = self.get_session(config) + self.koji_session = get_session(config) self.arches = sorted(arch.name for arch in self.module.arches) # Allow KojiModuleBuilder to be initialized if no arches are set but the module is in @@ -183,7 +87,7 @@ class KojiModuleBuilder(GenericBuilder): def getPerms(self): return dict([(p["name"], p["id"]) for p in self.koji_session.getAllPerms()]) - @module_build_service.utils.retry(wait_on=(IOError, koji.GenericError)) + @retry(wait_on=(IOError, koji.GenericError)) def buildroot_ready(self, artifacts=None): """ :param artifacts=None - list of nvrs @@ -234,7 +138,7 @@ class KojiModuleBuilder(GenericBuilder): reusable_module = get_reusable_module(module_build) if not reusable_module: return filtered_rpms - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) # Get all the RPMs and builds of the reusable module in Koji rpms, builds = koji_session.listTaggedRPMS(reusable_module.koji_tag, latest=True) # Convert the list to a dict where each key is the build_id @@ -468,59 +372,6 @@ class KojiModuleBuilder(GenericBuilder): log.debug("Wrote srpm into %s" % srpm_paths[0]) return srpm_paths[0] - @staticmethod - @module_build_service.utils.retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError)) - def get_session(config, login=True): - """Create and return a koji.ClientSession object - - :param config: the config object returned from :meth:`init_config`. - :type config: :class:`Config` - :param bool login: whether to log into the session. To login if True - is passed, otherwise not to log into session. - :return: the Koji session object. - :rtype: :class:`koji.ClientSession` - """ - koji_config = munch.Munch( - koji.read_config(profile_name=config.koji_profile, user_config=config.koji_config)) - # Timeout after 10 minutes. The default is 12 hours. - koji_config["timeout"] = 60 * 10 - - address = koji_config.server - log.info("Connecting to koji %r.", address) - koji_session = koji.ClientSession(address, opts=koji_config) - - if not login: - return koji_session - - authtype = koji_config.authtype - log.info("Authenticate session with %r.", authtype) - if authtype == "kerberos": - try: - import krbV - # We want to create a context per thread to avoid Kerberos cache corruption - ctx = krbV.Context() - except ImportError: - # If no krbV, we can assume GSSAPI auth is available - ctx = None - keytab = getattr(config, "krb_keytab", None) - principal = getattr(config, "krb_principal", None) - if not keytab and principal: - raise ValueError( - "The Kerberos keytab and principal aren't set for Koji authentication") - log.debug(" keytab: %r, principal: %r" % (keytab, principal)) - # We want to use the thread keyring for the ccache to ensure we have one cache per - # thread to avoid Kerberos cache corruption - ccache = "KEYRING:thread:mbs" - koji_session.krb_login(principal=principal, keytab=keytab, ctx=ctx, ccache=ccache) - elif authtype == "ssl": - koji_session.ssl_login( - os.path.expanduser(koji_config.cert), None, os.path.expanduser(koji_config.serverca) - ) - else: - raise ValueError("Unrecognized koji authtype %r" % authtype) - - return koji_session - def buildroot_connect(self, groups): log.info("%r connecting buildroot." % self) @@ -552,7 +403,7 @@ class KojiModuleBuilder(GenericBuilder): if "blocked_packages" in mbs_opts: self._koji_block_packages(mbs_opts["blocked_packages"]) - @module_build_service.utils.retry(wait_on=SysCallError, interval=5) + @retry(wait_on=SysCallError, interval=5) def add_groups(): return self._koji_add_groups_to_tag(dest_tag=self.module_build_tag, groups=groups) @@ -683,7 +534,7 @@ class KojiModuleBuilder(GenericBuilder): timeout = 60 * 60 # 60 minutes - @module_build_service.utils.retry(timeout=timeout, wait_on=koji.GenericError) + @retry(timeout=timeout, wait_on=koji.GenericError) def get_result(): log.debug("Waiting for task_id=%s to finish" % task_id) task = self.koji_session.getTaskResult(task_id) @@ -1169,7 +1020,7 @@ class KojiModuleBuilder(GenericBuilder): """ # If the component has not been built before, then None is returned. Instead, let's # return 0.0 so the type is consistent - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) return koji_session.getAverageBuildDuration(component) or 0.0 @classmethod @@ -1184,8 +1035,7 @@ class KojiModuleBuilder(GenericBuilder): :rtype: dict :return: {component_name: weight_as_float, ...} """ - - koji_session = KojiModuleBuilder.get_session(conf) + koji_session = get_session(conf) # Get our own userID, so we can limit the builds to only modular builds user_info = koji_session.getLoggedInUser() @@ -1280,7 +1130,7 @@ class KojiModuleBuilder(GenericBuilder): mmd.get_version(), mmd.get_context() ) - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) rpms = koji_session.listTaggedRPMS(build.koji_tag, latest=True)[0] nvrs = set(kobo.rpmlib.make_nvr(rpm, force_epoch=True) for rpm in rpms) return list(nvrs) @@ -1307,7 +1157,7 @@ class KojiModuleBuilder(GenericBuilder): :return: koji tag """ - session = KojiModuleBuilder.get_session(conf, login=False) + session = get_session(conf, login=False) rpm_md = session.getRPM(rpm) if not rpm_md: return None @@ -1333,7 +1183,7 @@ class KojiModuleBuilder(GenericBuilder): if not module.koji_tag: log.warning("No Koji tag associated with module %r", module) return [] - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) tag = koji_session.getTag(module.koji_tag) if not tag: raise ValueError("Unknown Koji tag %r." % module.koji_tag) diff --git a/module_build_service/builder/MockModuleBuilder.py b/module_build_service/builder/MockModuleBuilder.py index 67a526a3..a27e6741 100644 --- a/module_build_service/builder/MockModuleBuilder.py +++ b/module_build_service/builder/MockModuleBuilder.py @@ -11,10 +11,10 @@ import subprocess import threading from module_build_service import conf, log +from module_build_service.common.koji import get_session import module_build_service.scm import module_build_service.utils import module_build_service.scheduler - from module_build_service.builder import GenericBuilder from module_build_service.builder.utils import ( create_local_repo_from_koji_tag, @@ -579,7 +579,7 @@ class MockModuleBuilder(GenericBuilder): # Modules from local repository have already the RPMs filled in mmd. return mmd.get_rpm_artifacts() else: - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) rpms = koji_session.listTaggedRPMS(build.koji_tag, latest=True)[0] nvrs = set(kobo.rpmlib.make_nvr(rpm, force_epoch=True) for rpm in rpms) return list(nvrs) @@ -663,7 +663,7 @@ class SCMBuilder(BaseBuilder): if not self.koji_session: # If Koji is not configured on the system, then just return 0.0 for components try: - self.koji_session = KojiModuleBuilder.get_session(self.config, login=False) + self.koji_session = get_session(self.config, login=False) # If the component has not been built before, then None is returned. Instead, # let's return 0.0 so the type is consistent return self.koji_session.getAverageBuildDuration(component.package) or 0.0 diff --git a/module_build_service/builder/base.py b/module_build_service/builder/base.py index 0294dce1..bc7c3349 100644 --- a/module_build_service/builder/base.py +++ b/module_build_service/builder/base.py @@ -12,9 +12,7 @@ from abc import ABCMeta, abstractmethod from requests.exceptions import ConnectionError from module_build_service import conf, log -import module_build_service.resolver -import module_build_service.scm -import module_build_service.utils +from module_build_service.common.retry import retry from module_build_service.models import BUILD_STATES from module_build_service.resolver import GenericResolver from module_build_service.utils import create_dogpile_key_generator_func @@ -285,7 +283,7 @@ class GenericBuilder(six.with_metaclass(ABCMeta)): "default_buildroot_groups_" + str(module_build.id)) @classmethod - @module_build_service.utils.retry(wait_on=(ConnectionError)) + @retry(wait_on=(ConnectionError)) @default_buildroot_groups_cache.cache_on_arguments() def default_buildroot_groups(cls, db_session, module): try: diff --git a/module_build_service/common/__init__.py b/module_build_service/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/module_build_service/common/koji.py b/module_build_service/common/koji.py new file mode 100644 index 00000000..0c9bbcb9 --- /dev/null +++ b/module_build_service/common/koji.py @@ -0,0 +1,162 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: MIT +from __future__ import absolute_import +import os + +import koji +import munch +import six.moves.xmlrpc_client as xmlrpclib + +from module_build_service import log +from module_build_service.common.retry import retry +from module_build_service.errors import ProgrammingError + + +def koji_multicall_map(koji_session, koji_session_fnc, list_of_args=None, list_of_kwargs=None): + """ + Calls the `koji_session_fnc` using Koji multicall feature N times based on the list of + arguments passed in `list_of_args` and `list_of_kwargs`. + Returns list of responses sorted the same way as input args/kwargs. In case of error, + the error message is logged and None is returned. + + For example to get the package ids of "httpd" and "apr" packages: + ids = koji_multicall_map(session, session.getPackageID, ["httpd", "apr"]) + # ids is now [280, 632] + + :param KojiSessions koji_session: KojiSession to use for multicall. + :param object koji_session_fnc: Python object representing the KojiSession method to call. + :param list list_of_args: List of args which are passed to each call of koji_session_fnc. + :param list list_of_kwargs: List of kwargs which are passed to each call of koji_session_fnc. + """ + if list_of_args is None and list_of_kwargs is None: + raise ProgrammingError("One of list_of_args or list_of_kwargs must be set.") + + if ( + type(list_of_args) not in [type(None), list] + or type(list_of_kwargs) not in [type(None), list] + ): + raise ProgrammingError("list_of_args and list_of_kwargs must be list or None.") + + if list_of_kwargs is None: + list_of_kwargs = [{}] * len(list_of_args) + if list_of_args is None: + list_of_args = [[]] * len(list_of_kwargs) + + if len(list_of_args) != len(list_of_kwargs): + raise ProgrammingError("Length of list_of_args and list_of_kwargs must be the same.") + + koji_session.multicall = True + for args, kwargs in zip(list_of_args, list_of_kwargs): + if type(args) != list: + args = [args] + if type(kwargs) != dict: + raise ProgrammingError("Every item in list_of_kwargs must be a dict") + koji_session_fnc(*args, **kwargs) + + try: + responses = koji_session.multiCall(strict=True) + except Exception: + log.exception( + "Exception raised for multicall of method %r with args %r, %r:", + koji_session_fnc, args, kwargs, + ) + return None + + if not responses: + log.error("Koji did not return response for multicall of %r", koji_session_fnc) + return None + if type(responses) != list: + log.error( + "Fault element was returned for multicall of method %r: %r", koji_session_fnc, responses + ) + return None + + results = [] + + # For the response specification, see + # https://web.archive.org/web/20060624230303/http://www.xmlrpc.com/discuss/msgReader$1208?mode=topic + # Relevant part of this: + # Multicall returns an array of responses. There will be one response for each call in + # the original array. The result will either be a one-item array containing the result value, + # or a struct of the form found inside the standard element. + for response, args, kwargs in zip(responses, list_of_args, list_of_kwargs): + if type(response) == list: + if not response: + log.error( + "Empty list returned for multicall of method %r with args %r, %r", + koji_session_fnc, args, kwargs + ) + return None + results.append(response[0]) + else: + log.error( + "Unexpected data returned for multicall of method %r with args %r, %r: %r", + koji_session_fnc, args, kwargs, response + ) + return None + + return results + + +@retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError)) +def koji_retrying_multicall_map(*args, **kwargs): + """ + Retrying version of koji_multicall_map. This tries to retry the Koji call + in case of koji.GenericError or xmlrpclib.ProtocolError. + + Please refer to koji_multicall_map for further specification of arguments. + """ + return koji_multicall_map(*args, **kwargs) + + +@retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError)) +def get_session(config, login=True): + """Create and return a koji.ClientSession object + + :param config: the config object returned from :meth:`init_config`. + :type config: :class:`Config` + :param bool login: whether to log into the session. To login if True + is passed, otherwise not to log into session. + :return: the Koji session object. + :rtype: :class:`koji.ClientSession` + """ + koji_config = munch.Munch( + koji.read_config(profile_name=config.koji_profile, user_config=config.koji_config)) + # Timeout after 10 minutes. The default is 12 hours. + koji_config["timeout"] = 60 * 10 + + address = koji_config.server + log.info("Connecting to koji %r.", address) + koji_session = koji.ClientSession(address, opts=koji_config) + + if not login: + return koji_session + + authtype = koji_config.authtype + log.info("Authenticate session with %r.", authtype) + if authtype == "kerberos": + try: + import krbV + # We want to create a context per thread to avoid Kerberos cache corruption + ctx = krbV.Context() + except ImportError: + # If no krbV, we can assume GSSAPI auth is available + ctx = None + keytab = getattr(config, "krb_keytab", None) + principal = getattr(config, "krb_principal", None) + if not keytab and principal: + raise ValueError( + "The Kerberos keytab and principal aren't set for Koji authentication") + log.debug(" keytab: %r, principal: %r" % (keytab, principal)) + # We want to use the thread keyring for the ccache to ensure we have one cache per + # thread to avoid Kerberos cache corruption + ccache = "KEYRING:thread:mbs" + koji_session.krb_login(principal=principal, keytab=keytab, ctx=ctx, ccache=ccache) + elif authtype == "ssl": + koji_session.ssl_login( + os.path.expanduser(koji_config.cert), None, os.path.expanduser(koji_config.serverca) + ) + else: + raise ValueError("Unrecognized koji authtype %r" % authtype) + + return koji_session diff --git a/module_build_service/common/retry.py b/module_build_service/common/retry.py new file mode 100644 index 00000000..68f8071f --- /dev/null +++ b/module_build_service/common/retry.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: MIT +import functools +import time + +from module_build_service import conf, log + + +def retry(timeout=conf.net_timeout, interval=conf.net_retry_interval, wait_on=Exception): + """ A decorator that allows to retry a section of code... + ...until success or timeout. + """ + + def wrapper(function): + @functools.wraps(function) + def inner(*args, **kwargs): + start = time.time() + while True: + try: + return function(*args, **kwargs) + except wait_on as e: + log.warning( + "Exception %r raised from %r. Retry in %rs" % (e, function, interval) + ) + time.sleep(interval) + if (time.time() - start) >= timeout: + raise # This re-raises the last exception. + + return inner + + return wrapper diff --git a/module_build_service/resolver/KojiResolver.py b/module_build_service/resolver/KojiResolver.py index ad223eca..b54a09f5 100644 --- a/module_build_service/resolver/KojiResolver.py +++ b/module_build_service/resolver/KojiResolver.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT from itertools import groupby +from module_build_service.common.koji import get_session, koji_multicall_map from module_build_service.resolver.DBResolver import DBResolver from module_build_service import conf, models, log @@ -76,9 +77,6 @@ class KojiResolver(DBResolver): :param str stream: The requested stream name. :return list: Filtered list of builds. """ - # We need to import here because of circular dependencies. - from module_build_service.builder.KojiModuleBuilder import koji_multicall_map - # Return early if there are no module builds. if not module_builds: return [] @@ -128,9 +126,7 @@ class KojiResolver(DBResolver): if not tag: return [] - # Create KojiSession. We need to import here because of circular dependencies. - from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) event = koji_session.getLastEvent() # List all the modular builds in the modular Koji tag. diff --git a/module_build_service/scheduler/default_modules.py b/module_build_service/scheduler/default_modules.py index 7ac921bc..e81ac7db 100644 --- a/module_build_service/scheduler/default_modules.py +++ b/module_build_service/scheduler/default_modules.py @@ -11,13 +11,11 @@ import koji import six.moves.xmlrpc_client as xmlrpclib from module_build_service import conf, log, models, Modulemd, scm -from module_build_service.builder.KojiModuleBuilder import ( - koji_retrying_multicall_map, KojiModuleBuilder, -) +from module_build_service.common.koji import get_session, koji_retrying_multicall_map +from module_build_service.common.retry import retry from module_build_service.db_session import db_session from module_build_service.errors import UnprocessableEntity from module_build_service.resolver.base import GenericResolver -from module_build_service.utils import retry from module_build_service.utils.mse import ( get_compatible_base_module_mmds, expand_single_mse_streams) @@ -209,7 +207,7 @@ def _get_rawhide_version(): :return: the rawhide version (e.g. "f32") :rtype: str """ - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) build_target = koji_session.getBuildTarget("rawhide") if build_target: return build_target["build_tag_name"].partition("-build")[0] @@ -252,7 +250,7 @@ def handle_collisions_with_base_module_rpms(mmd, arches): "Querying Koji for the latest RPMs from the buildrequired base modules from the tags: %s", ", ".join(bm_tags), ) - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) bm_rpms = _get_rpms_from_tags(koji_session, list(bm_tags), arches) # The keys are base module RPM names and the values are sets of RPM NEVRAs with that name name_to_nevras = {} diff --git a/module_build_service/scheduler/handlers/components.py b/module_build_service/scheduler/handlers/components.py index 8781c87d..af93d559 100644 --- a/module_build_service/scheduler/handlers/components.py +++ b/module_build_service/scheduler/handlers/components.py @@ -7,7 +7,7 @@ import koji from module_build_service import celery_app, conf, models, log from module_build_service.builder import GenericBuilder -from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder +from module_build_service.common.koji import get_session from module_build_service.utils.general import mmd_to_str from module_build_service.db_session import db_session from module_build_service.scheduler import events @@ -90,7 +90,7 @@ def build_task_finalize( and conf.system in ["koji", "test"] and build_new_state == koji.BUILD_STATES["COMPLETE"] ): - koji_session = KojiModuleBuilder.get_session(conf) + koji_session = get_session(conf) rpms = koji_session.listBuildRPMs(component_build.nvr) mmd = parent.mmd() for artifact in rpms: diff --git a/module_build_service/scheduler/handlers/greenwave.py b/module_build_service/scheduler/handlers/greenwave.py index 73a6535c..be2c96f0 100644 --- a/module_build_service/scheduler/handlers/greenwave.py +++ b/module_build_service/scheduler/handlers/greenwave.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # SPDX-License-Identifier: MIT from module_build_service import celery_app, conf, log -from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder +from module_build_service.common.koji import get_session from module_build_service.db_session import db_session from module_build_service.models import ModuleBuild, BUILD_STATES from module_build_service.scheduler import events @@ -17,7 +17,7 @@ def get_corresponding_module_build(nvr): ``nvr``, None will be returned. :rtype: :class:`ModuleBuild` or None """ - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) build_info = koji_session.getBuild(nvr) if build_info is None: return None diff --git a/module_build_service/scheduler/handlers/modules.py b/module_build_service/scheduler/handlers/modules.py index 929710da..510b5b47 100644 --- a/module_build_service/scheduler/handlers/modules.py +++ b/module_build_service/scheduler/handlers/modules.py @@ -3,6 +3,7 @@ """ Handlers for module change events on the message bus. """ from module_build_service import celery_app, conf, models, log, build_logs +from module_build_service.common.retry import retry import module_build_service.resolver import module_build_service.utils from module_build_service.utils import ( @@ -257,7 +258,7 @@ def generate_module_build_koji_tag(build): return "-".join(["module", build.name, build.stream, build.version]) -@module_build_service.utils.retry( +@retry( interval=10, timeout=120, wait_on=(ValueError, RuntimeError, ConnectionError) ) def get_module_build_dependencies(build): @@ -336,7 +337,7 @@ def wait(msg_id, module_build_id, module_build_state): # Wait for the db on the frontend to catch up to the message, otherwise the # xmd information won't be present when we need it. # See https://pagure.io/fm-orchestrator/issue/386 - @module_build_service.utils.retry(interval=10, timeout=120, wait_on=RuntimeError) + @retry(interval=10, timeout=120, wait_on=RuntimeError) def _get_build_containing_xmd_for_mbs(): build = models.ModuleBuild.get_by_id(db_session, module_build_id) if "mbs" in build.mmd().get_xmd(): diff --git a/module_build_service/scheduler/producer.py b/module_build_service/scheduler/producer.py index 95737335..0b50e255 100644 --- a/module_build_service/scheduler/producer.py +++ b/module_build_service/scheduler/producer.py @@ -11,7 +11,7 @@ import module_build_service.scheduler import module_build_service.scheduler.consumer from module_build_service import celery_app, conf, models, log from module_build_service.builder import GenericBuilder -from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder +from module_build_service.common.koji import get_session from module_build_service.utils.greenwave import greenwave from module_build_service.db_session import db_session from module_build_service.scheduler.consumer import ON_MODULE_CHANGE_HANDLERS @@ -100,7 +100,7 @@ def fail_lost_builds(): if conf.system == "koji": # We don't do this on behalf of users - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) log.info("Querying tasks for statuses:") res = db_session.query(models.ComponentBuild).filter_by( state=koji.BUILD_STATES["BUILDING"] @@ -219,7 +219,7 @@ def retrigger_new_repo_on_failure(): if conf.system != "koji": return - koji_session = KojiModuleBuilder.get_session(conf) + koji_session = get_session(conf) module_builds = db_session.query(models.ModuleBuild).filter( models.ModuleBuild.state == models.BUILD_STATES["build"], models.ModuleBuild.new_repo_task_id.isnot(None), @@ -251,7 +251,7 @@ def delete_old_koji_targets(): now = datetime.utcnow() - koji_session = KojiModuleBuilder.get_session(conf) + koji_session = get_session(conf) for target in koji_session.getBuildTargets(): module = db_session.query(models.ModuleBuild).filter( models.ModuleBuild.koji_tag == target["dest_tag_name"], @@ -389,7 +389,7 @@ def sync_koji_build_tags(): if conf.system != "koji": return - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) threshold = datetime.utcnow() - timedelta(minutes=10) module_builds = db_session.query(models.ModuleBuild).filter( diff --git a/module_build_service/scm.py b/module_build_service/scm.py index a67ecbe8..529b000d 100644 --- a/module_build_service/scm.py +++ b/module_build_service/scm.py @@ -10,13 +10,14 @@ import shutil import datetime from module_build_service import log, conf +from module_build_service.common.retry import retry from module_build_service.errors import ( Forbidden, ValidationError, UnprocessableEntity, ProgrammingError, ) -from module_build_service.utils.general import scm_url_schemes, retry +from module_build_service.utils.general import scm_url_schemes class SCM(object): diff --git a/module_build_service/utils/general.py b/module_build_service/utils/general.py index 78e02155..36462733 100644 --- a/module_build_service/utils/general.py +++ b/module_build_service/utils/general.py @@ -1,10 +1,8 @@ # -*- coding: utf-8 -*- # SPDX-License-Identifier: MIT import os -import functools import inspect import hashlib -import time import locale import contextlib from datetime import datetime @@ -118,31 +116,6 @@ def scm_url_schemes(terse=False): return list(set(scheme_list)) -def retry(timeout=conf.net_timeout, interval=conf.net_retry_interval, wait_on=Exception): - """ A decorator that allows to retry a section of code... - ...until success or timeout. - """ - - def wrapper(function): - @functools.wraps(function) - def inner(*args, **kwargs): - start = time.time() - while True: - try: - return function(*args, **kwargs) - except wait_on as e: - log.warning( - "Exception %r raised from %r. Retry in %rs" % (e, function, interval) - ) - time.sleep(interval) - if (time.time() - start) >= timeout: - raise # This re-raises the last exception. - - return inner - - return wrapper - - def module_build_state_from_msg(msg): state = int(msg.module_build_state) # TODO better handling diff --git a/module_build_service/utils/ursine.py b/module_build_service/utils/ursine.py index 5eddb88e..4085fd6c 100644 --- a/module_build_service/utils/ursine.py +++ b/module_build_service/utils/ursine.py @@ -3,6 +3,7 @@ import re from module_build_service import conf, log +from module_build_service.common.koji import get_session from module_build_service.db_session import db_session from module_build_service.resolver import GenericResolver @@ -109,11 +110,9 @@ def get_modulemds_from_ursine_content(tag): modules metadata is found. :rtype: list[Modulemd.Module] """ - from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder - resolver = GenericResolver.create(db_session, conf) - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) repos = koji_session.getExternalRepoList(tag) build_tags = find_build_tags_from_external_repos(koji_session, repos) if not build_tags: @@ -252,12 +251,10 @@ def find_module_built_rpms(modules_nsvc): :rtype: list[str] """ import kobo.rpmlib - from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder - resolver = GenericResolver.create(db_session, conf) built_rpms = [] - koji_session = KojiModuleBuilder.get_session(conf, login=False) + koji_session = get_session(conf, login=False) for nsvc in modules_nsvc: name, stream, version, context = nsvc.split(":") diff --git a/tests/test_build/test_build.py b/tests/test_build/test_build.py index 42c820b4..66c9208b 100644 --- a/tests/test_build/test_build.py +++ b/tests/test_build/test_build.py @@ -555,7 +555,7 @@ class TestBuild(BaseTestBuild): assert module_build.module_builds_trace[4].state == models.BUILD_STATES["ready"] assert len(module_build.module_builds_trace) == 5 - @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @patch("module_build_service.builder.KojiModuleBuilder.get_session") @patch("module_build_service.auth.get_user", return_value=user) @patch("module_build_service.scm.SCM") def test_submit_build_buildonly( diff --git a/tests/test_builder/test_koji.py b/tests/test_builder/test_koji.py index c5e631f9..c0f2eda0 100644 --- a/tests/test_builder/test_koji.py +++ b/tests/test_builder/test_koji.py @@ -1,86 +1,84 @@ # -*- coding: utf-8 -*- # SPDX-License-Identifier: MIT +from collections import OrderedDict import os import shutil import tempfile -import mock import koji - -import six.moves.xmlrpc_client as xmlrpclib -from collections import OrderedDict +import mock +from mock import patch, MagicMock +import pytest import module_build_service.messaging import module_build_service.scheduler.handlers.repos import module_build_service.models from module_build_service import conf, Modulemd from module_build_service.db_session import db_session +from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder from module_build_service.builder import GenericBuilder from module_build_service.scheduler import events from module_build_service.utils.general import mmd_to_str - -import pytest -from mock import patch, MagicMock - from tests import init_data, clean_database, make_module_in_db -from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder + +@pytest.fixture(scope="function") +def mock_get_session(): + koji_session = MagicMock() + koji_session.getRepo.return_value = {"create_event": "fake event"} + + FakeKojiModuleBuilder.tags = { + "module-foo": { + "name": "module-foo", + "id": 1, + "arches": "x86_64", + "locked": False, + "perm": "admin", + }, + "module-foo-build": { + "name": "module-foo-build", + "id": 2, + "arches": "x86_64", + "locked": False, + "perm": "admin", + }, + } + + def _get_tag(name): + return FakeKojiModuleBuilder.tags.get(name, {}) + + koji_session.getTag = _get_tag + + def _createTag(name): + FakeKojiModuleBuilder.tags[name] = { + "name": name, + "id": len(FakeKojiModuleBuilder.tags) + 1, + "arches": "x86_64", + "locked": False, + "perm": "admin", + } + + koji_session.createTag = _createTag + + def _getBuildTarget(name): + return { + "build_tag_name": "module-foo-build", + "dest_tag_name": "module-foo", + } + + koji_session.getBuildTarget = _getBuildTarget + + def _getAllPerms(*args, **kwargs): + return [{"id": 1, "name": "admin"}] + + koji_session.getAllPerms = _getAllPerms + + with patch("module_build_service.builder.KojiModuleBuilder.get_session") as mock_get_session: + mock_get_session.return_value = koji_session + yield class FakeKojiModuleBuilder(KojiModuleBuilder): - @module_build_service.utils.retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError)) - def get_session(self, config, login=True): - koji_session = MagicMock() - koji_session.getRepo.return_value = {"create_event": "fake event"} - - FakeKojiModuleBuilder.tags = { - "module-foo": { - "name": "module-foo", - "id": 1, - "arches": "x86_64", - "locked": False, - "perm": "admin", - }, - "module-foo-build": { - "name": "module-foo-build", - "id": 2, - "arches": "x86_64", - "locked": False, - "perm": "admin", - }, - } - - def _get_tag(name): - return FakeKojiModuleBuilder.tags.get(name, {}) - - koji_session.getTag = _get_tag - - def _createTag(name): - FakeKojiModuleBuilder.tags[name] = { - "name": name, - "id": len(FakeKojiModuleBuilder.tags) + 1, - "arches": "x86_64", - "locked": False, - "perm": "admin", - } - - koji_session.createTag = _createTag - - def _getBuildTarget(name): - return { - "build_tag_name": self.module_build_tag["name"], - "dest_tag_name": self.module_tag["name"], - } - - koji_session.getBuildTarget = _getBuildTarget - - def _getAllPerms(*args, **kwargs): - return [{"id": 1, "name": "admin"}] - - koji_session.getAllPerms = _getAllPerms - - return koji_session - @classmethod def get_module_build_arches(cls, module): return ["x86_64"] @@ -102,7 +100,7 @@ class TestKojiBuilder: "server": "http://koji.example.com/", }, ) - self.mock_read_config = self.p_read_config.start() + self.p_read_config.start() def teardown_method(self, test_method): self.p_read_config.stop() @@ -120,7 +118,7 @@ class TestKojiBuilder: "/module-base-runtime-0.25-9/latest/x86_64" ) - def test_recover_orphaned_artifact_when_tagged(self): + def test_recover_orphaned_artifact_when_tagged(self, mock_get_session): """ Test recover_orphaned_artifact when the artifact is found and tagged in both tags """ module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) @@ -171,7 +169,7 @@ class TestKojiBuilder: assert component_build.state_reason == "Found existing build" assert builder.koji_session.tagBuild.call_count == 0 - def test_recover_orphaned_artifact_when_untagged(self): + def test_recover_orphaned_artifact_when_untagged(self, mock_get_session): """ Tests recover_orphaned_artifact when the build is found but untagged """ module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) @@ -216,7 +214,7 @@ class TestKojiBuilder: assert component_build.state_reason == "Found existing build" builder.koji_session.tagBuild.assert_called_once_with(2, "foo-1.0-1.{0}".format(dist_tag)) - def test_recover_orphaned_artifact_when_module_build_macros_untagged(self): + def test_recover_orphaned_artifact_when_module_build_macros_untagged(self, mock_get_session): """ Tests recover_orphaned_artifact when module-build-macros is found but untagged """ module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) @@ -272,7 +270,7 @@ class TestKojiBuilder: [mock.call(2, "srpm-build", "module-build-macros"), mock.call(2, "build", "module-build-macros")]) - def test_recover_orphaned_artifact_when_nothing_exists(self): + def test_recover_orphaned_artifact_when_nothing_exists(self, mock_get_session): """ Test recover_orphaned_artifact when the build is not found """ module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) @@ -309,7 +307,7 @@ class TestKojiBuilder: assert builder.koji_session.tagBuild.call_count == 0 @patch("koji.util") - def test_buildroot_ready(self, mocked_kojiutil): + def test_buildroot_ready(self, mocked_kojiutil, mock_get_session): module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) attrs = {"checkForBuilds.return_value": None, "checkForBuilds.side_effect": IOError} @@ -329,7 +327,7 @@ class TestKojiBuilder: assert mocked_kojiutil.checkForBuilds.call_count == 3 @pytest.mark.parametrize("blocklist", [False, True]) - def test_tagging_already_tagged_artifacts(self, blocklist): + def test_tagging_already_tagged_artifacts(self, blocklist, mock_get_session): """ Tests that buildroot_add_artifacts and tag_artifacts do not try to tag already tagged artifacts @@ -386,9 +384,8 @@ class TestKojiBuilder: builder.module_tag["id"], "new-1.0-1.module_e0095747" ) - @patch.object(FakeKojiModuleBuilder, "get_session") @patch.object(FakeKojiModuleBuilder, "_get_tagged_nvrs") - def test_untagged_artifacts(self, mock_get_tagged_nvrs, mock_get_session): + def test_untagged_artifacts(self, mock_get_tagged_nvrs,): """ Tests that only tagged artifacts will be untagged """ @@ -399,18 +396,20 @@ class TestKojiBuilder: {"name": "foobar", "id": 1}, {"name": "foobar-build", "id": 2}, ] - mock_get_session.return_value = mock_session mock_get_tagged_nvrs.side_effect = [["foo", "bar"], ["foo"]] - builder = FakeKojiModuleBuilder( - db_session=db_session, - owner=module_build.owner, - module=module_build, - config=conf, - tag_name="module-foo", - components=[], - ) + path = "module_build_service.builder.KojiModuleBuilder.get_session" + with patch(path) as mock_get_session: + mock_get_session.return_value = mock_session + builder = FakeKojiModuleBuilder( + db_session=db_session, + owner=module_build.owner, + module=module_build, + config=conf, + tag_name="module-foo", + components=[], + ) + builder.untag_artifacts(["foo", "bar"]) - builder.untag_artifacts(["foo", "bar"]) assert mock_session.untagBuild.call_count == 3 expected_calls = [mock.call(1, "foo"), mock.call(2, "foo"), mock.call(1, "bar")] assert mock_session.untagBuild.mock_calls == expected_calls @@ -534,7 +533,7 @@ class TestKojiBuilder: @pytest.mark.parametrize("custom_whitelist", [False, True]) @pytest.mark.parametrize("repo_include_all", [False, True]) def test_buildroot_connect( - self, custom_whitelist, blocklist, repo_include_all + self, custom_whitelist, blocklist, repo_include_all, mock_get_session ): module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) db_session.refresh(module_build) @@ -650,7 +649,7 @@ class TestKojiBuilder: assert session.editTag2.mock_calls == expected_calls @pytest.mark.parametrize("blocklist", [False, True]) - def test_buildroot_connect_create_tag(self, blocklist): + def test_buildroot_connect_create_tag(self, blocklist, mock_get_session): module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) db_session.refresh(module_build) @@ -688,7 +687,7 @@ class TestKojiBuilder: assert session.packageListBlock.mock_calls == expected_calls @pytest.mark.parametrize("scratch", [False, True]) - def test_buildroot_connect_create_target(self, scratch): + def test_buildroot_connect_create_target(self, scratch, mock_get_session): module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) if scratch: @@ -870,7 +869,7 @@ class TestKojiBuilder: "cg_enabled,cg_devel_enabled", [(False, False), (True, False), (True, True)] ) @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiContentGenerator") - def test_finalize(self, mock_koji_cg_cls, cg_enabled, cg_devel_enabled): + def test_finalize(self, mock_koji_cg_cls, cg_enabled, cg_devel_enabled, mock_get_session): module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2) db_session.refresh(module_build) module_build.state = 2 @@ -906,13 +905,6 @@ class TestKojiBuilder: else: mock_koji_cg.koji_import.assert_not_called() - @patch("koji.ClientSession") - def test_get_anonymous_session(self, ClientSession): - mbs_config = mock.Mock(koji_profile="koji", koji_config="conf/koji.conf") - session = KojiModuleBuilder.get_session(mbs_config, login=False) - assert ClientSession.return_value == session - assert ClientSession.return_value.krb_login.assert_not_called - @patch.dict("sys.modules", krbV=MagicMock()) @patch("koji.ClientSession") def test_ensure_builder_use_a_logged_in_koji_session(self, ClientSession): diff --git a/tests/test_common/__init__.py b/tests/test_common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_common/test_koji.py b/tests/test_common/test_koji.py new file mode 100644 index 00000000..16f4b1d3 --- /dev/null +++ b/tests/test_common/test_koji.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: MIT +import mock + +from module_build_service.common.koji import get_session + + +@mock.patch("koji.ClientSession") +def test_get_anonymous_session(mock_session): + mbs_config = mock.Mock(koji_profile="koji", koji_config="conf/koji.conf") + session = get_session(mbs_config, login=False) + assert mock_session.return_value == session + assert mock_session.return_value.krb_login.assert_not_called diff --git a/tests/test_resolver/test_koji.py b/tests/test_resolver/test_koji.py index f86ccd8c..008b4664 100644 --- a/tests/test_resolver/test_koji.py +++ b/tests/test_resolver/test_koji.py @@ -230,7 +230,7 @@ class TestLocalResolverModule: "testmodule-master-20170110091357.7c29193d", "testmodule-2-20180109091357.7c29193d"} - @patch("module_build_service.builder.KojiModuleBuilder.koji_multicall_map") + @patch("module_build_service.resolver.KojiResolver.koji_multicall_map") def test_filter_based_on_real_stream_name(self, koji_multicall_map): koji_session = MagicMock() koji_multicall_map.return_value = [ diff --git a/tests/test_scheduler/test_default_modules.py b/tests/test_scheduler/test_default_modules.py index 28bbfd07..185a8edb 100644 --- a/tests/test_scheduler/test_default_modules.py +++ b/tests/test_scheduler/test_default_modules.py @@ -256,18 +256,18 @@ def test_get_default_modules_invalid_branch( mock_scm.return_value.checkout_ref.assert_called_once_with("f32") -@patch("module_build_service.scheduler.default_modules.KojiModuleBuilder") -def test_get_rawhide_version(mock_koji_builder): +@patch("module_build_service.scheduler.default_modules.get_session") +def test_get_rawhide_version(mock_get_session): """ Test that _get_rawhide_version will return rawhide Fedora version. """ - mock_koji_builder.get_session.return_value.getBuildTarget.return_value = { + mock_get_session.return_value.getBuildTarget.return_value = { "build_tag_name": "f32-build", } assert default_modules._get_rawhide_version() == "f32" -@patch("module_build_service.scheduler.default_modules.KojiModuleBuilder.get_session") +@patch("module_build_service.scheduler.default_modules.get_session") @patch("module_build_service.scheduler.default_modules._get_rpms_from_tags") def test_handle_collisions_with_base_module_rpms(mock_grft, mock_get_session): """ diff --git a/tests/test_scheduler/test_repo_done.py b/tests/test_scheduler/test_repo_done.py index 07b562c9..beefe774 100644 --- a/tests/test_scheduler/test_repo_done.py +++ b/tests/test_scheduler/test_repo_done.py @@ -42,7 +42,7 @@ class TestRepoDone: "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready", return_value=True, ) - @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @mock.patch("module_build_service.builder.KojiModuleBuilder.get_session") @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build") @mock.patch( "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect" @@ -87,7 +87,7 @@ class TestRepoDone: "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready", return_value=True, ) - @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @mock.patch("module_build_service.builder.KojiModuleBuilder.get_session") @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build") @mock.patch( "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect" @@ -141,7 +141,7 @@ class TestRepoDone: "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready", return_value=True, ) - @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @mock.patch("module_build_service.builder.KojiModuleBuilder.get_session") @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build") @mock.patch( "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect" @@ -203,7 +203,7 @@ class TestRepoDone: "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready", return_value=True, ) - @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @mock.patch("module_build_service.builder.KojiModuleBuilder.get_session") @mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build") @mock.patch( "module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect" diff --git a/tests/test_scheduler/test_tag_tagged.py b/tests/test_scheduler/test_tag_tagged.py index 48eae474..8b7cb58b 100644 --- a/tests/test_scheduler/test_tag_tagged.py +++ b/tests/test_scheduler/test_tag_tagged.py @@ -43,7 +43,7 @@ class TestTagTagged: "module_build_service.builder.GenericBuilder.default_buildroot_groups", return_value={"build": [], "srpm-build": []}, ) - @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @patch("module_build_service.builder.KojiModuleBuilder.get_session") @patch("module_build_service.builder.GenericBuilder.create_from_module") def test_newrepo(self, create_builder, koji_get_session, dbg): """ @@ -132,7 +132,7 @@ class TestTagTagged: "module_build_service.builder.GenericBuilder.default_buildroot_groups", return_value={"build": [], "srpm-build": []}, ) - @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @patch("module_build_service.builder.KojiModuleBuilder.get_session") @patch("module_build_service.builder.GenericBuilder.create_from_module") def test_newrepo_still_building_components( self, create_builder, koji_get_session, dbg @@ -184,7 +184,7 @@ class TestTagTagged: "module_build_service.builder.GenericBuilder.default_buildroot_groups", return_value={"build": [], "srpm-build": []}, ) - @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @patch("module_build_service.builder.KojiModuleBuilder.get_session") @patch("module_build_service.builder.GenericBuilder.create_from_module") def test_newrepo_failed_components(self, create_builder, koji_get_session, dbg): """ @@ -256,7 +256,7 @@ class TestTagTagged: "module_build_service.builder.GenericBuilder.default_buildroot_groups", return_value={"build": [], "srpm-build": []}, ) - @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @patch("module_build_service.builder.KojiModuleBuilder.get_session") @patch("module_build_service.builder.GenericBuilder.create_from_module") def test_newrepo_multiple_batches_tagged( self, create_builder, koji_get_session, dbg @@ -358,7 +358,7 @@ class TestTagTagged: "module_build_service.builder.GenericBuilder.default_buildroot_groups", return_value={"build": [], "srpm-build": []}, ) - @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @patch("module_build_service.builder.KojiModuleBuilder.get_session") @patch("module_build_service.builder.GenericBuilder.create_from_module") def test_newrepo_build_time_only(self, create_builder, koji_get_session, dbg): """ @@ -450,7 +450,7 @@ class TestTagTagged: "module_build_service.builder.GenericBuilder.default_buildroot_groups", return_value={"build": [], "srpm-build": []}, ) - @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session") + @patch("module_build_service.builder.KojiModuleBuilder.get_session") @patch("module_build_service.builder.GenericBuilder.create_from_module") def test_newrepo_not_duplicated( self, create_builder, koji_get_session, dbg, task_state, expect_new_repo