toddlers/tests/plugins/test_distgit_bugzilla_sync.py
Michal Konečný d9c03e08ce Fix formatting for for black > 23
Signed-off-by: Michal Konečný <mkonecny@redhat.com>
2023-02-03 14:33:39 +01:00

1359 lines
46 KiB
Python

import datetime
import json
import logging
import os
import re
import time
from unittest.mock import call, MagicMock, Mock, patch
import xmlrpc
import pytest
from toddlers.plugins.distgit_bugzilla_sync import DistgitBugzillaSync, main
@pytest.fixture
def config():
"""Test configuration for toddler fixture."""
return {
# toddlers level config values
"email_overrides_file": "dummy_file",
"dist_git_url": "https://src.fedoraproject.org",
"mail_server": "bastion",
"admin_email": "root@localhost",
"pdc_config": {
"server": "https://pdc.fedoraproject.org/rest_api/v1",
},
# distgit_bugzilla_sync config values
"ignorable_accounts": [],
"fasjson": False,
"default_qa_contact": "nurgle@fedoraproject.org",
"notify_admins": ["root@localhost.localdomain"],
"pdc_types": {
"rpms": "rpm",
},
"products": {
"Fedora": {"namespace": "rpms", "versions": ["rawhide", 33, 32, 31]},
"Fedora EPEL": {
"branch_regex": r"^e(pe)?l\d+$",
"versions": ["epel8", "epel7", "el6"],
},
},
}
def mock_bz_mail(mail, mail_overrides):
"""Mock method for getting mail of user or group."""
mails = {
"Nurgle": "nurgle@fedoraproject.org",
"Khorne": "khorne@fedoraproject.org",
"Tzeentch": "tzeentch@fedoraproject.org",
"Slaanesh": "slaanesh@fedoraproject.org",
"Chaos": "chaos@fedoraproject.org",
"orphan": "orphan@fedoraproject.org",
}
return mails[mail]
def mock_bz_mail_limited(mail, mail_overrides):
"""Mock method for getting mail of user or group with limited return."""
mails = {
"Tzeentch": "tzeentch@fedoraproject.org",
}
return mails.get(mail, None)
class TestDistgitBugzillaSyncToddler:
toddler_cls = DistgitBugzillaSync
def test_accepts_topic_invalid(self, toddler):
assert toddler.accepts_topic("foo.bar") is False
@pytest.mark.parametrize(
"topic",
[
"org.fedoraproject.*.toddlers.trigger.distgit_bugzilla_sync",
"org.fedoraproject.prod.toddlers.trigger.distgit_bugzilla_sync",
"org.fedoraproject.stg.toddlers.trigger.distgit_bugzilla_sync",
],
)
def test_accepts_topic_valid(self, toddler, topic):
assert toddler.accepts_topic(topic)
def test_process_no_email_override_file(self, toddler):
"""Assert that the exception is raised when e-mail overrides file is not provided."""
with pytest.raises(KeyError) as exc:
toddler.process(
config={},
message={},
)
assert exc.value.args[0] == "email_overrides_file"
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_dry_run_edit_project(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that dry run with edit is processed correctly."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {"foo": "Summary"}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {"rpms": {"foo": ["Slaanesh"]}}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {"foo": [["f32", True], ["epel8", True]]}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {"foo": "dummy"}
toddler.process(config=config, message={}, dry_run=True)
mock_toml.assert_called_with("dummy_file")
assert toddler.namespace_to_product == {"rpms": "Fedora"}
assert toddler.product_to_branch_regex == {
"Fedora EPEL": re.compile(r"^e(pe)?l\d+$")
}
assert toddler.branch_regex_to_product == {
re.compile(r"^e(pe)?l\d+$"): "Fedora EPEL"
}
assert len(toddler.errors) == 0
mock_summaries.assert_called_with(config)
assert toddler.requests_session.get.mock_calls == [
call(config["dist_git_url"] + "/extras/pagure_poc.json", timeout=120),
call(config["dist_git_url"] + "/extras/pagure_bz.json", timeout=120),
call("https://pdc.fedoraproject.org/extras/active_branches.json"),
]
assert toddler.pagure_projects == [
{
"namespace": "rpms",
"name": "foo",
"poc": "Khorne",
"epelpoc": "Tzeentch",
"watchers": ["Slaanesh"],
"summary": "Summary",
"branches": [["f32", True], ["epel8", True]],
"products": [
"Fedora",
"Fedora EPEL",
],
"products_poc": {
"Fedora": "Khorne",
"Fedora EPEL": "Tzeentch",
},
"products_retired": {
"Fedora": False,
"Fedora EPEL": False,
},
}
]
assert mock_bugzilla.get_product_info_packages.mock_calls == [
call("Fedora"),
call("Fedora EPEL"),
]
assert mock_bugzilla.edit_component.mock_calls == [
call(
owner="khorne@fedoraproject.org",
product="Fedora",
package="foo",
component="dummy",
cc_list=["slaanesh@fedoraproject.org", "khorne@fedoraproject.org"],
versions=["rawhide", 33, 32, 31],
description="Summary",
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
retired=False,
print_fas_names=False,
print_no_change=False,
dry_run=True,
),
call(
owner="tzeentch@fedoraproject.org",
product="Fedora EPEL",
package="foo",
component="dummy",
cc_list=["slaanesh@fedoraproject.org", "tzeentch@fedoraproject.org"],
versions=["epel8", "epel7", "el6"],
description="Summary",
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
retired=False,
print_fas_names=False,
print_no_change=False,
dry_run=True,
),
]
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_dry_run_add_project(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that dry run with add is processed correctly."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {"foo": "Summary"}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {"rpms": {"foo": ["Slaanesh"]}}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {"foo": [["f32", True], ["epel8", True]]}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {}
toddler.process(config=config, message={}, dry_run=True)
mock_toml.assert_called_with("dummy_file")
assert toddler.namespace_to_product == {"rpms": "Fedora"}
assert toddler.product_to_branch_regex == {
"Fedora EPEL": re.compile(r"^e(pe)?l\d+$")
}
assert toddler.branch_regex_to_product == {
re.compile(r"^e(pe)?l\d+$"): "Fedora EPEL"
}
assert len(toddler.errors) == 0
mock_summaries.assert_called_with(config)
assert toddler.requests_session.get.mock_calls == [
call(config["dist_git_url"] + "/extras/pagure_poc.json", timeout=120),
call(config["dist_git_url"] + "/extras/pagure_bz.json", timeout=120),
call("https://pdc.fedoraproject.org/extras/active_branches.json"),
]
assert toddler.pagure_projects == [
{
"namespace": "rpms",
"name": "foo",
"poc": "Khorne",
"epelpoc": "Tzeentch",
"watchers": ["Slaanesh"],
"summary": "Summary",
"branches": [["f32", True], ["epel8", True]],
"products": [
"Fedora",
"Fedora EPEL",
],
"products_poc": {
"Fedora": "Khorne",
"Fedora EPEL": "Tzeentch",
},
"products_retired": {
"Fedora": False,
"Fedora EPEL": False,
},
}
]
assert mock_bugzilla.get_product_info_packages.mock_calls == [
call("Fedora"),
call("Fedora EPEL"),
]
assert mock_bugzilla.add_component.mock_calls == [
call(
product="Fedora",
owner="khorne@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["slaanesh@fedoraproject.org", "khorne@fedoraproject.org"],
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=True,
),
call(
product="Fedora EPEL",
owner="tzeentch@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["slaanesh@fedoraproject.org", "tzeentch@fedoraproject.org"],
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=True,
),
]
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_dry_run_specific_project(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that dry run is processed only for the specified project."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {
"foo": "Summary",
"bar": "Summary",
}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {
"foo": {"fedora": "Khorne", "epel": "Tzeentch"},
"bar": {"fedora": "Khorne", "epel": "Tzeentch"},
}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {
"rpms": {
"foo": ["Slaanesh"],
"bar": ["Slaanesh"],
}
}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {
"foo": [["f32", True], ["epel8", True]],
"bar": [["f32", True], ["epel8", True]],
}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {}
toddler.process(config=config, message={}, projects=["rpms/foo"], dry_run=True)
assert toddler.pagure_projects == [
{
"namespace": "rpms",
"name": "foo",
"poc": "Khorne",
"epelpoc": "Tzeentch",
"watchers": ["Slaanesh"],
"summary": "Summary",
"branches": [["f32", True], ["epel8", True]],
"products": [
"Fedora",
"Fedora EPEL",
],
"products_poc": {
"Fedora": "Khorne",
"Fedora EPEL": "Tzeentch",
},
"products_retired": {
"Fedora": False,
"Fedora EPEL": False,
},
}
]
assert mock_bugzilla.add_component.mock_calls == [
call(
product="Fedora",
owner="khorne@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["slaanesh@fedoraproject.org", "khorne@fedoraproject.org"],
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=True,
),
call(
product="Fedora EPEL",
owner="tzeentch@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["slaanesh@fedoraproject.org", "tzeentch@fedoraproject.org"],
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=True,
),
]
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toddlers.plugins.distgit_bugzilla_sync.notify")
@patch("toml.load")
def test_process_report_protocol_error(
self,
mock_toml,
mock_notify,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
tmpdir,
):
"""Assert that `xmlrpc.client.ProtocolError` is reported correctly."""
# Adjust config
config["temp_folder"] = tmpdir
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {
"foo": "Summary",
}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {
"rpms": {
"foo": ["Slaanesh"],
}
}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {"foo": [["f32", True], ["epel8", True]]}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {}
mock_bugzilla.add_component.side_effect = xmlrpc.client.ProtocolError(
"https://bugzilla.com",
10,
"The name khorne@fedoraproject.org is not a valid username",
{},
)
toddler.process(config=config, message={}, dry_run=False)
assert mock_bugzilla.add_component.mock_calls == [
call(
product="Fedora",
owner="khorne@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["slaanesh@fedoraproject.org", "khorne@fedoraproject.org"],
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=False,
),
]
assert toddler.errors == {
"bugzilla_raw": ["()"],
"bugzilla": [
"Failed to update: `Fedora/foo`:\n"
" <ProtocolError for https://bugzilla.com: 10 "
"The name khorne@fedoraproject.org is not a valid username>\n"
" ()"
],
"PDC": [],
"configuration": [],
"mails": [],
}
report = [
"ERROR REPORT",
"bugzilla",
" - Failed to update: `Fedora/foo`:\n"
" <ProtocolError for https://bugzilla.com: 10 "
"The name khorne@fedoraproject.org is not a valid username>\n"
" ()",
"",
]
mock_notify.notify_admins_distgit_sync_error.assert_called_with(
"bastion", "root@localhost", ["root@localhost.localdomain"], report
)
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toddlers.plugins.distgit_bugzilla_sync.notify")
@patch("toml.load")
def test_process_report_client_error(
self,
mock_toml,
mock_notify,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
tmpdir,
):
"""Assert that `xmlrpc.client.Error` is reported correctly."""
# Adjust config
config["temp_folder"] = tmpdir
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {
"foo": "Summary",
}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {
"rpms": {
"foo": ["Slaanesh"],
}
}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {"foo": [["f32", True], ["epel8", True]]}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {}
mock_bugzilla.add_component.side_effect = xmlrpc.client.Error(
"The name khorne@fedoraproject.org is not a valid username"
)
toddler.process(config=config, message={}, dry_run=False)
assert mock_bugzilla.add_component.mock_calls == [
call(
product="Fedora",
owner="khorne@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["slaanesh@fedoraproject.org", "khorne@fedoraproject.org"],
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=False,
),
call(
product="Fedora EPEL",
owner="tzeentch@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["slaanesh@fedoraproject.org", "tzeentch@fedoraproject.org"],
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"slaanesh@fedoraproject.org": "Slaanesh",
"tzeentch@fedoraproject.org": "Tzeentch",
},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=False,
),
]
assert toddler.errors == {
"bugzilla_raw": [
"foo -- The name khorne@fedoraproject.org is not a valid username",
"foo -- The name khorne@fedoraproject.org is not a valid username",
],
"bugzilla": [
"Failed to update: `Fedora/foo`:\n"
" Error('The name khorne@fedoraproject.org is not a valid username')\n"
" ('The name khorne@fedoraproject.org is not a valid username',)",
"Failed to update: `Fedora EPEL/foo`:\n"
" Error('The name khorne@fedoraproject.org is not a valid username')\n"
" ('The name khorne@fedoraproject.org is not a valid username',)",
],
"PDC": [],
"configuration": [],
"mails": [],
}
report = [
"ERROR REPORT",
"bugzilla",
" - Failed to update: `Fedora/foo`:\n"
" Error('The name khorne@fedoraproject.org is not a valid username')\n"
" ('The name khorne@fedoraproject.org is not a valid username',)\n"
" - Failed to update: `Fedora EPEL/foo`:\n"
" Error('The name khorne@fedoraproject.org is not a valid username')\n"
" ('The name khorne@fedoraproject.org is not a valid username',)",
"",
]
mock_notify.notify_admins_distgit_sync_error.assert_called_with(
"bastion", "root@localhost", ["root@localhost.localdomain"], report
)
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toddlers.plugins.distgit_bugzilla_sync.notify")
@patch("toml.load")
def test_process_report_missing_mails(
self,
mock_toml,
mock_notify,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that missing bugzilla e-mails are reported correctly."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {
"foo": "Summary",
}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {
"rpms": {
"foo": ["Slaanesh"],
}
}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {"foo": [["f32", True], ["epel8", True]]}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail_limited
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {}
toddler.process(config=config, message={}, dry_run=False)
assert mock_bugzilla.add_component.mock_calls == [
call(
product="Fedora EPEL",
owner="tzeentch@fedoraproject.org",
package="foo",
qa_contact="nurgle@fedoraproject.org",
cc_list=["tzeentch@fedoraproject.org"],
fas_users_info={"tzeentch@fedoraproject.org": "Tzeentch"},
description="Summary",
retired=False,
print_fas_names=False,
dry_run=False,
),
]
assert toddler.errors == {
"bugzilla": [],
"PDC": [],
"configuration": [],
"mails": [
"`Slaanesh` has no bugzilla_email or mailing_list set on `Fedora/foo`",
"`Khorne` has no bugzilla_email or mailing_list set on `Fedora/foo`",
"`Slaanesh` has no bugzilla_email or mailing_list set on `Fedora EPEL/foo`",
],
}
report = [
"ERROR REPORT",
"mails",
" - `Slaanesh` has no bugzilla_email or mailing_list set on `Fedora/foo`\n"
" - `Khorne` has no bugzilla_email or mailing_list set on `Fedora/foo`\n"
" - `Slaanesh` has no bugzilla_email or mailing_list set on `Fedora EPEL/foo`",
"",
]
mock_notify.notify_admins_distgit_sync_error.assert_called_with(
"bastion", "root@localhost", ["root@localhost.localdomain"], report
)
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_dry_run_verbose(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
caplog,
):
"""Assert that dry run with verbose is processed correctly."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {"foo": "Summary"}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {"rpms": {"foo": ["Slaanesh"]}}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {"foo": [["f32", True], ["epel8", True]]}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail_limited
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {"foo": "dummy"}
with caplog.at_level(logging.DEBUG):
toddler.process(config=config, message={}, dry_run=True)
assert "Building a cache of the rpm package summaries" in caplog.text
assert (
"Querying '{}' for points of contact.".format(
config["dist_git_url"] + "/extras/pagure_poc.json"
)
in caplog.text
)
assert (
"Querying '{}' for initial cc list.".format(
config["dist_git_url"] + "/extras/pagure_bz.json"
)
in caplog.text
)
assert "Querying PDC for EOL information." in caplog.text
assert "Building bugzilla's products in-memory cache" in caplog.text
assert "Querying bugzilla but not doing anything" in caplog.text
assert (
"********************************************************************************"
in caplog.text
)
assert (
"ERROR REPORT\n"
"mails\n"
" - `Slaanesh` has no bugzilla_email or mailing_list set on `Fedora/foo`\n"
" - `Khorne` has no bugzilla_email or mailing_list set on `Fedora/foo`\n"
" - `Slaanesh` has no bugzilla_email or mailing_list set on `Fedora EPEL/foo`\n"
in caplog.text
)
assert "Building the data structure" in caplog.text
assert "Building the FAS cache" in caplog.text
assert "Building the bugzilla cache" in caplog.text
assert "Interacting with bugzilla" in caplog.text
assert "Total" in caplog.text
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_missing_namespace(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that namespace missing in config is processed correctly."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {"foo": "Summary"}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"modules": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {"modules": {"foo": ["Slaanesh"]}}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {"foo": [["f32", True], ["epel8", True]]}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {"foo": "dummy"}
toddler.process(config=config, message={}, dry_run=True)
mock_bugzilla.edit_component.assert_not_called()
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_missing_pdc_branches(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that dry run with edit is processed correctly."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {"foo": "Summary"}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {"rpms": {"foo": ["Slaanesh"]}}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {"foo": "dummy"}
toddler.process(config=config, message={}, dry_run=True)
assert toddler.errors == {
"bugzilla": [],
"PDC": [
"No PDC branch found for rpms/foo",
],
"configuration": [],
"mails": [],
}
mock_bugzilla.edit_component.assert_not_called()
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_orphaned_project(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that dry run with edit is processed correctly."""
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {"foo": "Summary"}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {"rpms": {"foo": ["@Chaos"]}}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {
"foo": [["f32", False], ["epel8", False]],
}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
mock_fas.get_bz_email_group.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {"foo": "dummy"}
toddler.process(config=config, message={}, dry_run=True)
assert toddler.pagure_projects == [
{
"namespace": "rpms",
"name": "foo",
"poc": "Khorne",
"epelpoc": "Tzeentch",
"watchers": ["@Chaos"],
"summary": "Summary",
"branches": [["f32", False], ["epel8", False]],
"products": [
"Fedora",
"Fedora EPEL",
],
"products_poc": {
"Fedora": "orphan",
"Fedora EPEL": "Tzeentch",
},
"products_retired": {
"Fedora": True,
"Fedora EPEL": True,
},
}
]
assert mock_bugzilla.edit_component.mock_calls == [
call(
owner="orphan@fedoraproject.org",
product="Fedora",
package="foo",
component="dummy",
cc_list=["chaos@fedoraproject.org", "orphan@fedoraproject.org"],
versions=["rawhide", 33, 32, 31],
description="Summary",
fas_users_info={
"orphan@fedoraproject.org": "orphan",
"chaos@fedoraproject.org": "@Chaos",
"tzeentch@fedoraproject.org": "Tzeentch",
},
retired=True,
print_fas_names=False,
print_no_change=False,
dry_run=True,
),
call(
owner="tzeentch@fedoraproject.org",
product="Fedora EPEL",
package="foo",
component="dummy",
cc_list=["chaos@fedoraproject.org", "tzeentch@fedoraproject.org"],
versions=["epel8", "epel7", "el6"],
description="Summary",
fas_users_info={
"orphan@fedoraproject.org": "orphan",
"chaos@fedoraproject.org": "@Chaos",
"tzeentch@fedoraproject.org": "Tzeentch",
},
retired=True,
print_fas_names=False,
print_no_change=False,
dry_run=True,
),
]
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toml.load")
def test_process_ignorrable_account(
self,
mock_toml,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
):
"""Assert that dry run with edit is processed correctly."""
# Adjust config
config["ignorable_accounts"] = ["Slaanesh"]
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {"foo": "Summary"}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {"rpms": {"foo": ["Slaanesh"]}}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {
"foo": [["f32", True], ["epel8", True]],
}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {"foo": "dummy"}
toddler.process(config=config, message={}, dry_run=True)
assert mock_bugzilla.edit_component.mock_calls == [
call(
owner="khorne@fedoraproject.org",
product="Fedora",
package="foo",
component="dummy",
cc_list=["khorne@fedoraproject.org"],
versions=["rawhide", 33, 32, 31],
description="Summary",
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"tzeentch@fedoraproject.org": "Tzeentch",
},
retired=False,
print_fas_names=False,
print_no_change=False,
dry_run=True,
),
call(
owner="tzeentch@fedoraproject.org",
product="Fedora EPEL",
package="foo",
component="dummy",
cc_list=["tzeentch@fedoraproject.org"],
versions=["epel8", "epel7", "el6"],
description="Summary",
fas_users_info={
"khorne@fedoraproject.org": "Khorne",
"tzeentch@fedoraproject.org": "Tzeentch",
},
retired=False,
print_fas_names=False,
print_no_change=False,
dry_run=True,
),
]
@patch(
"toddlers.plugins.distgit_bugzilla_sync.PackageSummaries.get_package_summaries"
)
@patch("toddlers.plugins.distgit_bugzilla_sync.fedora_account")
@patch("toddlers.plugins.distgit_bugzilla_sync.bugzilla_system")
@patch("toddlers.plugins.distgit_bugzilla_sync.notify")
@patch("toml.load")
def test_process_notify_user_cache_exists(
self,
mock_toml,
mock_notify,
mock_bugzilla,
mock_fas,
mock_summaries,
config,
toddler,
tmpdir,
):
"""Assert that user_cache is used if exists."""
# Adjust config
config["temp_folder"] = tmpdir
# Prepare user cache
data = {
"khorne@fedoraproject.org": {
"last_update": time.mktime(datetime.datetime.utcnow().timetuple())
}
}
with open(os.path.join(tmpdir, "user_cache.json"), "w") as stream:
json.dump(data, stream)
# Mock toml load
email_overrides = Mock()
mock_toml.return_value = email_overrides
# Mock package summaries response
mock_summaries.return_value = {
"foo": "Summary",
}
# Mock pagure responses
toddler.requests_session = Mock()
response_pagure_poc = MagicMock()
response_pagure_poc.json.return_value = {
"rpms": {"foo": {"fedora": "Khorne", "epel": "Tzeentch"}}
}
response_pagure_cc = MagicMock()
response_pagure_cc.json.return_value = {
"rpms": {
"foo": ["Slaanesh"],
}
}
# Mock PDC response
response_pdc = MagicMock()
response_pdc.json.return_value = {
"rpm": {
"foo": [["f32", True], ["epel8", True]],
}
}
toddler.requests_session.get.side_effect = (
response_pagure_poc,
response_pagure_cc,
response_pdc,
)
# Mock FAS
mock_fas.get_bz_email_user.side_effect = mock_bz_mail
# Mock bugzilla
mock_bugzilla.get_product_info_packages.return_value = {}
mock_bugzilla.add_component.side_effect = xmlrpc.client.Error(
"The name khorne@fedoraproject.org is not a valid username"
)
toddler.process(config=config, message={}, dry_run=False)
mock_notify.notify_packager_distgit_sync_error.assert_not_called()
with open(os.path.join(tmpdir, "user_cache.json")) as stream:
assert "khorne@fedoraproject.org" in stream.read()
class TestMain:
"""Test class for `toddler.plugins.distgit_bugzilla_sync.main`."""
def test_main_no_args(self, capsys):
"""Assert that help is printed if no arg is provided."""
with pytest.raises(SystemExit):
main([])
out, err = capsys.readouterr()
assert out == ""
# Expecting something along these lines, but don't make the test too tight:
#
# usage: pytest [-h] [--dry-run] [-q | --debug] conf [username]
# pytest: error: the following arguments are required: conf
assert err.startswith("usage:")
assert "error: the following arguments are required:" in err
@patch("toml.load", new=Mock(return_value={}))
def test_main_debug(self, caplog):
"""Assert that debug is set correctly."""
with pytest.raises(KeyError, match=r"'email_overrides_file'"):
main(["test.cfg", "--debug"])
assert "Failed to load the file containing the email-overrides" in caplog.text
@patch("toml.load", new=Mock(return_value={}))
def test_main(self, caplog):
"""Assert that INFO log level is handled correctly."""
with pytest.raises(KeyError, match=r"'email_overrides_file'"):
main(["test.cfg"])
assert "Failed to load the file containing the email-overrides" in caplog.text