koji_retired_packages: modify koji session and make it testable locally
Signed-off-by: Lenka Segura <lsegura@redhat.com>
This commit is contained in:
parent
a6dfc2e084
commit
ca595a3846
3 changed files with 124 additions and 28 deletions
|
@ -3,7 +3,7 @@ Unit tests for `toddler.plugins.koji_block_retired`
|
|||
"""
|
||||
|
||||
import logging
|
||||
from unittest.mock import MagicMock
|
||||
from unittest import mock
|
||||
|
||||
import koji
|
||||
import pytest
|
||||
|
@ -56,7 +56,7 @@ class TestProcess:
|
|||
config = {"key": "value"}
|
||||
message = "Example message"
|
||||
|
||||
self.toddler_cls.process_block_retired = MagicMock()
|
||||
self.toddler_cls.process_block_retired = mock.MagicMock()
|
||||
self.toddler_cls.process(config, message)
|
||||
self.toddler_cls.process_block_retired.assert_called_once_with(config, message)
|
||||
|
||||
|
@ -70,16 +70,18 @@ class TestProcessBlockRetired:
|
|||
def setup_method(self):
|
||||
"""Initialize toddler."""
|
||||
self.toddler_cls = koji_block_retired.KojiBlockRetired()
|
||||
self.toddler_cls.koji_session = MagicMock()
|
||||
self.toddler_cls.koji_session = mock.MagicMock()
|
||||
|
||||
def test_no_dead_package_file(self, caplog):
|
||||
"""
|
||||
Assert that if no dead package was added the plugin stops.
|
||||
"""
|
||||
caplog.set_level(logging.INFO)
|
||||
message = MagicMock()
|
||||
message = mock.MagicMock()
|
||||
message.body = {"commit": {"stats": {"files": {}}}}
|
||||
self.toddler_cls.process_block_retired({}, message)
|
||||
config = mock.MagicMock()
|
||||
config = {"profile": "stg"}
|
||||
self.toddler_cls.process_block_retired(config, message)
|
||||
assert caplog.records[-1].message == "No dead.package in the commit, bailing"
|
||||
|
||||
def test_dead_package_not_added(self, caplog):
|
||||
|
@ -87,13 +89,15 @@ class TestProcessBlockRetired:
|
|||
Assert if in commit dead package wasn't added the plugin stops.
|
||||
"""
|
||||
caplog.set_level(logging.INFO)
|
||||
message = MagicMock()
|
||||
message = mock.MagicMock()
|
||||
message.body = {
|
||||
"commit": {
|
||||
"stats": {"files": {"dead.package": {"additions": 0, "deletions": 1}}}
|
||||
}
|
||||
}
|
||||
self.toddler_cls.process_block_retired({}, message)
|
||||
config = mock.MagicMock()
|
||||
config = {"profile": "stg"}
|
||||
self.toddler_cls.process_block_retired(config, message)
|
||||
assert caplog.records[-1].message == "dead.package file was not added, bailing"
|
||||
|
||||
def test_dead_package_added_to_main_branch(self, caplog):
|
||||
|
@ -101,7 +105,8 @@ class TestProcessBlockRetired:
|
|||
Assert that that main branch will be changed to rawhide tag
|
||||
"""
|
||||
caplog.set_level(logging.INFO)
|
||||
message = MagicMock()
|
||||
|
||||
message = mock.MagicMock()
|
||||
message.body = {
|
||||
"commit": {
|
||||
"stats": {"files": {"dead.package": {"additions": 1, "deletions": 0}}},
|
||||
|
@ -110,7 +115,9 @@ class TestProcessBlockRetired:
|
|||
"namespace": "example_ns",
|
||||
}
|
||||
}
|
||||
self.toddler_cls.process_block_retired({}, message)
|
||||
config = mock.MagicMock()
|
||||
config = {"profile": "stg"}
|
||||
self.toddler_cls.process_block_retired(config, message)
|
||||
self.toddler_cls.koji_session.packageListBlock.assert_called_once_with(
|
||||
taginfo="rawhide",
|
||||
pkginfo="example-repo",
|
||||
|
@ -121,7 +128,7 @@ class TestProcessBlockRetired:
|
|||
Assert that method will process correctly with different branches.
|
||||
"""
|
||||
caplog.set_level(logging.INFO)
|
||||
message = MagicMock()
|
||||
message = mock.MagicMock()
|
||||
message.body = {
|
||||
"commit": {
|
||||
"stats": {"files": {"dead.package": {"additions": 1, "deletions": 0}}},
|
||||
|
@ -130,7 +137,9 @@ class TestProcessBlockRetired:
|
|||
"namespace": "example_ns",
|
||||
}
|
||||
}
|
||||
self.toddler_cls.process_block_retired({}, message)
|
||||
config = mock.MagicMock()
|
||||
config = {"profile": "stg"}
|
||||
self.toddler_cls.process_block_retired(config, message)
|
||||
self.toddler_cls.koji_session.packageListBlock.assert_called_once_with(
|
||||
taginfo="f38",
|
||||
pkginfo="example-repo",
|
||||
|
@ -140,7 +149,7 @@ class TestProcessBlockRetired:
|
|||
"""
|
||||
Assert that Koji generic error will be handled correctly.
|
||||
"""
|
||||
message = MagicMock()
|
||||
message = mock.MagicMock()
|
||||
message.body = {
|
||||
"commit": {
|
||||
"stats": {"files": {"dead.package": {"additions": 1, "deletions": 0}}},
|
||||
|
@ -149,6 +158,13 @@ class TestProcessBlockRetired:
|
|||
"namespace": "example_ns",
|
||||
}
|
||||
}
|
||||
self.toddler_cls.koji_session.packageListBlock.side_effect = koji.GenericError
|
||||
self.toddler_cls.process_block_retired({}, message)
|
||||
assert caplog.records[-1].message == "Failed to process Koji block retired"
|
||||
config = mock.MagicMock()
|
||||
config = {"profile": "stg"}
|
||||
self.toddler_cls.koji_session.packageListBlock.side_effect = koji.GenericError(
|
||||
"Failed"
|
||||
)
|
||||
with pytest.raises(koji.GenericError):
|
||||
self.toddler_cls.process_block_retired(config, message)
|
||||
assert (
|
||||
caplog.records[-1].message == "Failed to process Koji block retired: Failed"
|
||||
)
|
||||
|
|
|
@ -176,6 +176,10 @@ email_overrides_url = "https://pagure.io/fedora-infra/ansible/raw/master/f/roles
|
|||
[consumer_config.clean_retired_packages]
|
||||
pdc_active_branches = "https://pdc.fedoraproject.org/extras/active_branches.json"
|
||||
|
||||
[consumer_config.koji_block_retired]
|
||||
# Use "stg" for testing, "koji" for prod
|
||||
profile = "stg"
|
||||
|
||||
[consumer_config.packagers_without_bugzilla]
|
||||
ignorable_namespaces = ["tests"]
|
||||
|
||||
|
|
|
@ -4,17 +4,18 @@ When a branch is retired, automatically blocks the package on Koji
|
|||
Authors: Anton Medvedev <amedvede@redhat.com>
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from fedora_messaging_git_hook_messages import CommitV1
|
||||
import koji
|
||||
import toml
|
||||
|
||||
|
||||
from ..base import ToddlerBase
|
||||
|
||||
# Koji hub url for creating ClientSession
|
||||
KOJIHUB_URL = "https://koji.fedoraproject.org/kojihub"
|
||||
# Koji hub staging url for creating ClientSession
|
||||
KOJIHUB_STG_URL = "https://koji.stg.fedoraproject.org/kojihub"
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -32,15 +33,15 @@ class KojiBlockRetired(ToddlerBase):
|
|||
def __init__(self):
|
||||
self.koji_session = None
|
||||
|
||||
def _create_session(self, profile):
|
||||
"""Makes a koji session, that handles logging in"""
|
||||
koji_module = koji.get_profile_module(profile)
|
||||
self.koji_session = koji_module.ClientSession(koji_module.config.server)
|
||||
|
||||
def accepts_topic(self, topic):
|
||||
"""Returns a boolean whether this toddler is interested in messages
|
||||
from this specific topic.
|
||||
"""
|
||||
if topic.startswith("org.fedoraproject.stg"):
|
||||
self.koji_session = koji.ClientSession(KOJIHUB_STG_URL)
|
||||
else:
|
||||
self.koji_session = koji.ClientSession(KOJIHUB_URL)
|
||||
|
||||
return topic.startswith("org.fedoraproject.") and topic.endswith("git.receive")
|
||||
|
||||
def process(self, config, message):
|
||||
|
@ -55,6 +56,8 @@ class KojiBlockRetired(ToddlerBase):
|
|||
"""
|
||||
msg = message.body
|
||||
|
||||
profile = config["profile"]
|
||||
|
||||
# If there is no dead.package file in commit, then it can be ignored
|
||||
if "dead.package" not in msg["commit"]["stats"]["files"]:
|
||||
_log.info("No dead.package in the commit, bailing")
|
||||
|
@ -77,8 +80,81 @@ class KojiBlockRetired(ToddlerBase):
|
|||
|
||||
_log.info("Processing Koji block retired for %s", repo)
|
||||
|
||||
if self.koji_session is None:
|
||||
self._create_session(profile)
|
||||
|
||||
try:
|
||||
self.koji_session.packageListBlock(taginfo=branch_name, pkginfo=repo)
|
||||
except koji.GenericError:
|
||||
_log.exception("Failed to process Koji block retired")
|
||||
return
|
||||
except (koji.GenericError, koji.ActionNotAllowed) as e:
|
||||
_log.exception(f"Failed to process Koji block retired: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def get_arguments(args):
|
||||
"""Load and parse the CLI arguments."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Checks that packagers have a valid bugzilla account"
|
||||
)
|
||||
parser.add_argument(
|
||||
"conf",
|
||||
help="Configuration file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
dest="message",
|
||||
help="In case you want a certain message to be processed "
|
||||
"for local testing, pass it as a file",
|
||||
)
|
||||
log_level_group = parser.add_mutually_exclusive_group()
|
||||
log_level_group.add_argument(
|
||||
"-q",
|
||||
"--quiet",
|
||||
action="store_const",
|
||||
dest="log_level",
|
||||
const=logging.WARNING,
|
||||
default=logging.INFO,
|
||||
help="Be less talkative",
|
||||
)
|
||||
log_level_group.add_argument(
|
||||
"--debug",
|
||||
action="store_const",
|
||||
dest="log_level",
|
||||
const=logging.DEBUG,
|
||||
help="Enable debugging output",
|
||||
)
|
||||
|
||||
return parser.parse_args(args)
|
||||
|
||||
|
||||
def main(args):
|
||||
"""Schedule the first test and run the scheduler."""
|
||||
args = get_arguments(args)
|
||||
logging.StreamHandler(stream=sys.stdout)
|
||||
config = toml.load(args.conf)
|
||||
logging.basicConfig(level=args.log_level)
|
||||
msg_file = args.message
|
||||
|
||||
# For local testing: In case you want to run a specific message
|
||||
if msg_file:
|
||||
# Either from a file
|
||||
with open(msg_file, "r") as stream:
|
||||
msg = json.load(stream)
|
||||
commit_msg = CommitV1(body=msg["body"], headers=msg["headers"], topic=msg["topic"])
|
||||
else:
|
||||
# Or edit this dict to match your needs
|
||||
body = {"commit": {"branch": "rawhide", "stats": {"files": {}}}, "repo": "repo"}
|
||||
commit_msg = CommitV1(body=body)
|
||||
|
||||
logging.StreamHandler(stream=sys.stdout)
|
||||
|
||||
KojiBlockRetired().process(
|
||||
config=config.get("consumer_config", {}).get("koji_block_retired", {}),
|
||||
message=commit_msg,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
try:
|
||||
main(sys.argv[1:])
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue