From 91c13afb27d93ef13960681ee49a06d1133703ff Mon Sep 17 00:00:00 2001 From: FrantiĊĦek Zatloukal Date: Oct 26 2020 16:39:27 +0000 Subject: Unit tests --- diff --git a/.gitignore b/.gitignore index 6371fb5..25bf069 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.egg-info venv .venv +.tox/ # Misc .vscode/ diff --git a/oraculum/__init__.py b/oraculum/__init__.py index e3eb38d..75645a2 100644 --- a/oraculum/__init__.py +++ b/oraculum/__init__.py @@ -58,6 +58,16 @@ class ReverseProxied(object): environ['wsgi.url_scheme'] = scheme return self.app(environ, start_response) +class TestingBugzilla(): + + def getbug(self, bugid): + return + + def url_to_query(self, url): + return + + def query(self, query): + return # Flask App app = Flask(__name__) @@ -160,10 +170,15 @@ celery_app.conf.update( from .utils import cache_utils # NOQA: E402 CACHE = cache_utils.Cached(max_cache_age=app.config['MAX_DB_AGE']) -BUGZILLA = bugzilla.Bugzilla("bugzilla.redhat.com", - tokenfile="/tmp/python-bugzilla-token-%d" % os.getpid(), - cookiefile="/tmp/python-bugzilla-cookie-%d" % os.getpid(), - force_rest=True) + +# let's not connect to the internet while in testing run +if not app.config["TESTING"]: + BUGZILLA = bugzilla.Bugzilla("bugzilla.redhat.com", + tokenfile="/tmp/python-bugzilla-token-%d" % os.getpid(), + cookiefile="/tmp/python-bugzilla-cookie-%d" % os.getpid(), + force_rest=True) +else: + BUGZILLA = TestingBugzilla() CORS(app, supports_credentials=True) diff --git a/oraculum/utils/orphans.py b/oraculum/utils/orphans.py index dc9f4d6..d74086d 100644 --- a/oraculum/utils/orphans.py +++ b/oraculum/utils/orphans.py @@ -108,94 +108,3 @@ def get_orphans(packages, orphans_data=None): for package in packages: orphans[package] = graph.get_package_info(package) return orphans - - -if __name__ == "__main__": - def test_orphans(): - """ - * notes packages being orphaned - A -- B -- C* - -- D* -- E* - -- E* - -- F* - """ - DATA = { - "affected_packages": { - 'A': ['B', 'F'], - 'B': ['C', 'D', 'E'], - 'C': [], - 'D': ['E'], - 'E': [], - 'F': [] - }, - "status_change": { - 'C': '2020-01-01T00:00:00', - 'D': '2020-01-01T00:00:01', - 'E': '2020-01-01T00:00:02', - 'F': '2020-01-01T00:00:03', - - } - } - out = get_orphans(["A", "F", "Z"], DATA) - # Not affected - o_z = { - "orphaned": False, - "depends_on_orphaned": False, - "direct_dependencies": [], - "remote_dependencies": [], - "problematic_since": None, - "dot_graph": "", - "vis_js": {"nodes": [], "edges": []} - } - assert out["Z"] == o_z - - # Directly orphaned - o_f = { - "orphaned": True, - "depends_on_orphaned": False, - "direct_dependencies": [], - "remote_dependencies": [], - "problematic_since": '2020-01-01T00:00:03', - "dot_graph": "", - "vis_js": {"nodes": [], "edges": []} - } - assert out["F"] == o_f - - # Complete example - o_a = { - "orphaned": False, - "depends_on_orphaned": True, - "direct_dependencies": ['F'], - "remote_dependencies": ['C', 'D', 'E'], - "problematic_since": '2020-01-01T00:00:00' - } - dg = sorted(out["A"]["dot_graph"].split('\n')) - vis_js = out["A"]["vis_js"] - del(out["A"]["dot_graph"]) - del(out["A"]["vis_js"]) - - out["A"]["remote_dependencies"].sort() - assert out["A"] == o_a - - o_dg = sorted([ - '"A" -- "B" -- "C";', - '"A" -- "B" -- "D";', - '"A" -- "B" -- "E";', - '"A" -- "F";' - ]) - assert o_dg == dg - - assert len(vis_js.keys()) == 2 - assert 'nodes' in vis_js.keys() - assert 'edges' in vis_js.keys() - - nodes = sorted([(n['id'], n['label']) for n in vis_js['nodes']]) - assert nodes == [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E'), (5, 'F')] - - edges = sorted([(e['from'], e['to']) for e in vis_js['edges']]) - assert edges == [(0, 1), (0, 5), (1, 2), (1, 3), (1, 4)] - - print("OK") - - - test_orphans() diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/__init__.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..c9bb71f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,7 @@ +def pytest_configure(config): + """This is a bit of a hack to detect whether or not we are running inside + a test environment""" + import os + + # make sure that the testing config is used + os.environ['TEST'] = 'true' diff --git a/tests/test_packager_dashboard_bodhi.py b/tests/test_packager_dashboard_bodhi.py new file mode 100644 index 0000000..3ad4f4f --- /dev/null +++ b/tests/test_packager_dashboard_bodhi.py @@ -0,0 +1,280 @@ +from bodhi.client.bindings import BodhiClient + +import pytest +import mock +import munch + +from oraculum.utils import bodhi +from oraculum import app, CACHE + +# Mock data START +mocked_override_data = [ + munch.Munch( + {'notes': 'Needed to rebuild xyz', + 'submission_date': '2020-10-20 05:30:29', + 'expiration_date': '2020-10-27 05:30:28', + 'expired_date': None, + 'build_id': 9999999, + 'submitter_id': 999, + 'nvr': 'package_o-2.2-1.fc99', + 'build': + munch.Munch( + { + 'nvr': 'package_o-2.2-1.fc99', + 'signed': True, + 'release_id': 333, + 'type': 'rpm', + 'epoch': 0 + }), + 'submitter': + munch.Munch( + {'id': 1111, + 'name': 'packager', + 'email': 'packager@domain.com', + 'avatar': '', + 'openid': 'packager.id.fedoraproject.org', + 'groups': [munch.Munch({'name': 'packager'}), munch.Munch({'name': 'provenpackager'}), munch.Munch({'name': 'python-sig'})]})} + )] + +mocked_update_data = [{ + "alias": "FEDORA-2020-3f9a07db44", + "autokarma": True, + "autotime": True, + "bugs": [], + "builds": [ + { + "epoch": 0, + "nvr": "gjs-1.66.1-2.fc98", + "release_id": 40, + "signed": True, + "type": "rpm" + }, + { + "epoch": 0, + "nvr": "mozjs78-78.4.0-1.fc98", + "release_id": 40, + "signed": True, + "type": "rpm" + } + ], + "close_bugs": True, + "comments": [ + {}, + {} + ], + "compose": None, + "content_type": "rpm", + "critpath": True, + "date_approved": None, + "date_modified": "2020-10-20 09:15:46", + "date_pushed": None, + "date_stable": None, + "date_submitted": "2020-10-20 09:15:27", + "date_testing": "2020-10-20 14:22:18", + "display_name": "", + "from_tag": None, + "karma": 2, + "locked": False, + "meets_testing_requirements": True, + "notes": "Some note about the update\n", + "pushed": True, + "release": { + "branch": "f98", + "candidate_tag": "f98-updates-candidate", + "composed_by_bodhi": True, + "composes": [], + "create_automatic_updates": False, + "dist_tag": "f98", + "id_prefix": "FEDORA", + "long_name": "Fedora 98", + "mail_template": "fedora_errata_template", + "name": "F98", + "override_tag": "f98-override", + "package_manager": "dnf", + "pending_signing_tag": "f98-signing-pending", + "pending_stable_tag": "f98-updates-pending", + "pending_testing_tag": "f98-updates-testing-pending", + "stable_tag": "f98-updates", + "state": "current", + "testing_repository": "updates-testing", + "testing_tag": "f98-updates-testing", + "version": "98" + }, + "request": "stable", + "require_bugs": True, + "require_testcases": True, + "requirements": None, + "severity": "unspecified", + "stable_days": 14, + "stable_karma": 1, + "status": "testing", + "suggest": "reboot", + "test_cases": [], + "test_gating_status": "ignored", + "title": "gjs-1.66.1-2.fc98 mozjs78-78.4.0-1.fc98", + "type": "enhancement", + "unstable_karma": -3, + "updateid": "FEDORA-2020-3f9a07db44", + "url": "https://bodhi.fedoraproject.org/updates/FEDORA-2020-3f9a07db44", + "user": { + "avatar": "", + "email": "developer@domain.com", + "groups": [ + { + "name": "packager" + }, + { + "name": "qa-tools-sig" + } + ], + "id": 2240, + "name": "developer", + "openid": "developer.id.fedoraproject.org" + }, + "version_hash": "d7f551d00f81b4392d0055f47312a3292863be6e" + }] + +# Mock data END + +class dotdict(dict): + # https://stackoverflow.com/a/23689767 + """dot.notation access to dictionary attributes""" + __getattr__ = dict.get + __setattr__ = dict.__setitem__ + __delattr__ = dict.__delitem__ + +class MockedBodhiClient(): + + def __init__(self, **kwargs): + return + + def list_overrides(self, **kwargs): + if "page" in kwargs and kwargs["page"] == 2: + return dotdict({ + "pages": 2, + "page": 2, + "overrides": [mocked_override_data] + }) + return dotdict({ + "pages": 2, + "page": 1, + "overrides": [mocked_override_data] + }) + + def query(**kwargs): + if "page" in kwargs and kwargs["page"] == 2: + return dotdict({ + "pages": 2, + "page": 2, + "updates": [mocked_update_data] + }) + return dotdict({ + "pages": 2, + "page": 1, + "updates": [mocked_update_data] + }) + +class TestBodhi(object): + + + mocked_bodhi_updates_resp = {"F98": mocked_update_data} + + stub_fedora_releases = { + "oldstable": 96, + "stable": 97, + "branched": 98, + "rawhide": 99, + "values": [96, 97, 98, 99] + } + + def test_updates(self, monkeypatch): + + expected_result_single_package = { + 'gjs': [ + { + 'comments': 2, + 'karma': 2, + 'pretty_name': 'gjs-1.66.1-2.fc98', + 'release': 'Fedora 98', + 'stable_by_time': '2020-11-03 09:15:46', + 'status': 'testing', + 'submission_date': '2020-10-20 09:15:27', + 'updateid': 'FEDORA-2020-3f9a07db44', + 'url': 'https://bodhi.fedoraproject.org/updates/FEDORA-2020-3f9a07db44' + } + ] + } + + + expected_result_multiple_packages = { + 'gjs': [ + { + 'comments': 2, + 'karma': 2, + 'pretty_name': 'gjs-1.66.1-2.fc98 mozjs78-78.4.0-1.fc98', + 'release': 'Fedora 98', + 'stable_by_time': '2020-11-03 09:15:46', + 'status': 'testing', + 'submission_date': '2020-10-20 09:15:27', + 'updateid': 'FEDORA-2020-3f9a07db44', + 'url': 'https://bodhi.fedoraproject.org/updates/FEDORA-2020-3f9a07db44' + } + ], + 'mozjs78': [ + { + 'comments': 2, + 'karma': 2, + 'pretty_name': 'gjs-1.66.1-2.fc98 mozjs78-78.4.0-1.fc98', + 'release': 'Fedora 98', + 'stable_by_time': '2020-11-03 09:15:46', + 'status': 'testing', + 'submission_date': '2020-10-20 09:15:27', + 'updateid': 'FEDORA-2020-3f9a07db44', + 'url': 'https://bodhi.fedoraproject.org/updates/FEDORA-2020-3f9a07db44' + } + ] + } + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + assert bodhi.get_updates(["gjs", "mozjs78"], self.mocked_bodhi_updates_resp) == expected_result_multiple_packages + + self.mocked_bodhi_updates_resp["F98"][0]["title"] = "gjs-1.66.1-2.fc98" + assert bodhi.get_updates(["gjs"], self.mocked_bodhi_updates_resp) == expected_result_single_package + + expected_result_single_package["package_b"] = [] + assert bodhi.get_updates(["gjs", "package_b"], self.mocked_bodhi_updates_resp) == expected_result_single_package + + assert bodhi.get_updates([], self.mocked_bodhi_updates_resp) == {} + + def test_overrides(self, monkeypatch): + + expected_result = { + 'package_o': [ + { + 'expiration_date': '2020-10-27 05:30:28', + 'pretty_name': 'package_o-2.2-1.fc99', + 'release': 'Fedora Rawhide', + 'submission_date': '2020-10-20 05:30:29', + 'url': 'https://bodhi.fedoraproject.org/overrides/package_o-2.2-1.fc99' + } + ] + } + + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + assert bodhi.get_user_overrides(["package_o"], mocked_override_data) == expected_result + + expected_result["package_a"] = [] + assert bodhi.get_user_overrides(["package_o", "package_a"], mocked_override_data) == expected_result + assert bodhi.get_user_overrides([], mocked_override_data) == {} + + def test_bodhi_updates_query(self, monkeypatch): + + # We are testing also the result pagination here, + # both pages with the same results... if you wondered why is such a weird list below + assert bodhi.query_bodhi(MockedBodhiClient, "F98", pending=False) == [mocked_update_data, mocked_update_data] + + def test_bodhi_overrides_query(self, monkeypatch): + + monkeypatch.setattr(bodhi, 'BodhiClient', MockedBodhiClient) + assert bodhi.get_overrides() == [mocked_override_data, mocked_override_data] diff --git a/tests/test_packager_dashboard_bugzilla.py b/tests/test_packager_dashboard_bugzilla.py new file mode 100644 index 0000000..a4c7be5 --- /dev/null +++ b/tests/test_packager_dashboard_bugzilla.py @@ -0,0 +1,146 @@ +import pytest +import mock + +from oraculum.utils import bugzilla +from oraculum import app, CACHE, BUGZILLA + + +class dotdict(dict): + # https://stackoverflow.com/a/23689767 + """dot.notation access to dictionary attributes""" + __getattr__ = dict.get + __setattr__ = dict.__setitem__ + __delattr__ = dict.__delitem__ + +def bz_advanced_releases_stub(what): + if "fedora_releases" in what: + return { + "oldstable": 96, + "stable": 97, + "branched": 98, + "rawhide": 99, + "values": [96, 97, 98, 99] + } + if "ftbfs_trackers" in what: + return [1,2] + if "fti_trackers" in what: + return [3,4] + if "blocker_trackers" in what: + return [5,6] + +def bz_query(query): + dct = { + "summary": "Some bug description", + "creator": "Happy Tester", + "id": 1, + "blocks": [], + "severity": "unspecified", + "priority": "unspecified", + "status": "NEW", + "last_change_time": "2020-10-01T12:21:44Z", + "creation_time": "2020-01-24T22:08:29Z", + "version": "97", + "keywords": [], + "whiteboard": "", + "comments": [None, None] + } + + if query["pkg_name"] == "package_b": + dct["blocks"] = [5] + dct["whiteboard"] = "AcceptedBlocker" + dct["version"] = "rawhide" + + if query["pkg_name"] == "package_c": + dct["blocks"] = [6] + dct["whiteboard"] = "ProposedBlocker" + dct["version"] = "98" + + if query["pkg_name"] == "package_d": + dct["blocks"] = [1] + + if query["pkg_name"] == "package_e": + dct["blocks"] = [3] + dct["version"] = "96" + + if query["pkg_name"] == "package_f": + dct["summary"] = "[fedora-all]Some bug description" + dct["priority"] = "high" + dct["severity"] = "urgent" + + return [dotdict(dct)] + + +class TestBugzilla(object): + + + stub_fedora_releases = { + "oldstable": 96, + "stable": 97, + "branched": 98, + "rawhide": 99, + "values": [96, 97, 98, 99] + } + + def test_trackers(self, monkeypatch): + + expected_result = [961111, 971111, 981111, 991111] + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + monkeypatch.setattr(BUGZILLA, 'getbug', lambda req: dotdict({"id": int(req[1:3] + "1111")})) + + # Blockers aren't fetched for anything else than Rawhide and Branched + assert bugzilla.get_blocker_trackers() == [981111, 981111, 991111, 991111] + + assert bugzilla.get_ftbfs_trackers() == expected_result + assert bugzilla.get_fti_trackers() == expected_result + + def test_package_bugs(self, monkeypatch): + + expected_result = [{ + 'bug_id': 1, + 'comments': 1, + 'keywords': [], + 'modified': '2020-10-01 12:21:44', + 'priority': 'unspecified', + 'priority_severity': 'unspecified', + 'release': 'Fedora 97', + 'reported': '2020-01-24 22:08:29', + 'severity': 'unspecified', + 'status': 'NEW', + 'title': 'Some bug description', + 'url': 'https://bugzilla.redhat.com/1' + }] + + expected_result_b = [{**expected_result[0]}] + expected_result_c = [{**expected_result[0]}] + expected_result_d = [{**expected_result[0]}] + expected_result_e = [{**expected_result[0]}] + expected_result_f = [{**expected_result[0]}] + + expected_result_b[0]["keywords"] = ["AcceptedBlocker"] + expected_result_b[0]["release"] = "Fedora Rawhide" + + expected_result_c[0]["keywords"] = ["ProposedBlocker"] + expected_result_c[0]["release"] = "Fedora 98" + + expected_result_d[0]["keywords"] = ["FTBFS"] + + expected_result_e[0]["keywords"] = ["FTI"] + expected_result_e[0]["release"] = "Fedora 96" + + expected_result_f[0]["priority"] = "high" + expected_result_f[0]["severity"] = "urgent" + expected_result_f[0]["release"] = "Fedora" + expected_result_f[0]["title"] = "[fedora-all]Some bug description" + expected_result_f[0]["priority_severity"] = "urgent" + + monkeypatch.setattr(CACHE, 'get', bz_advanced_releases_stub) + monkeypatch.setattr(BUGZILLA, 'url_to_query', lambda url: {"pkg_name": url.split("component=")[1]}) + monkeypatch.setattr(BUGZILLA, 'query', bz_query) + + assert bugzilla.get_package_bugs("package_a") == expected_result # Normal F97 bug + assert bugzilla.get_package_bugs("package_b") == expected_result_b # F99 Accepted Blocker + assert bugzilla.get_package_bugs("package_c") == expected_result_c # F98 Proposed Blocker + assert bugzilla.get_package_bugs("package_d") == expected_result_d # F97 FTBFS + assert bugzilla.get_package_bugs("package_e") == expected_result_e # F96 FTI + assert bugzilla.get_package_bugs("package_f") == expected_result_f # Fedora CVE, High priotiy, Urgent severity diff --git a/tests/test_packager_dashboard_health_check.py b/tests/test_packager_dashboard_health_check.py new file mode 100644 index 0000000..3447874 --- /dev/null +++ b/tests/test_packager_dashboard_health_check.py @@ -0,0 +1,77 @@ +from bodhi.client.bindings import BodhiClient + +import pytest +import mock + +from oraculum.utils import health_check +from oraculum import app, CACHE + + +class TestHealthCheck(object): + + stub_fedora_releases = { + "oldstable": 96, + "stable": 97, + "branched": 98, + "rawhide": 99, + "values": [96, 97, 98, 99] + } + + mocked_basic_health_check_data = { + "98": { + "package_a": { + "noarch": { + "reason": ["chromium"], + "since": "2020-07-17T07:47:25.219142397Z" + } + } + } + } + + def health_advanced_releases_stub(self, what): + if "fedora_releases" in what: + return self.stub_fedora_releases + + if "health_check_data" in what: + return self.mocked_basic_health_check_data + + + def test_get_data_structure(self, monkeypatch): + + expected_result = { + "96": {}, + "96-testing": {}, + "97": {}, + "97-testing": {}, + "98": {}, + "98-testing": {}, + "rawhide": {}, + } + + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + monkeypatch.setattr(health_check, 'process_health_check_json', mock.MagicMock(return_value={})) + + assert health_check.get_health_check_data() == expected_result + + def test_get_health_check_user_data(self, monkeypatch): + + expected_result_basic = { + 'package_a': [ + { + 'problems':{ + 'noarch': { + 'reason': ['chromium'], + 'since': '2020-07-17T07:47:25.219142397Z' + } + }, + 'release': 'Fedora 98', + 'repo': 'stable' + } + ] + } + + + monkeypatch.setattr(CACHE, 'get', self.health_advanced_releases_stub) + assert health_check.get_health_check_user_data(["package_a"]) == expected_result_basic + assert health_check.get_health_check_user_data(["package_b"]) == {'package_b': []} diff --git a/tests/test_packager_dashboard_helpers.py b/tests/test_packager_dashboard_helpers.py new file mode 100644 index 0000000..30e04ef --- /dev/null +++ b/tests/test_packager_dashboard_helpers.py @@ -0,0 +1,94 @@ +import pytest +import mock +import fedfind.helpers + +from oraculum.utils import dashboard_helpers +from oraculum import app, CACHE + + +class TestDashboardHelpers(object): + + + stub_fedora_releases = { + "oldstable": 96, + "stable": 97, + "branched": 98, + "rawhide": 99, + "values": [96, 97, 98, 99] + } + + def test_release_is_active(self, monkeypatch): + + # Force EPEL Releases for tests + # This is usually defined in settings.py by real values, so we can't put it in config.py TEST block + app.config["EPEL_RELEASES"] = [1, 2] + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + + assert dashboard_helpers.release_is_active("Fedora Rawhide") + assert dashboard_helpers.release_is_active("Fedora 97") + assert dashboard_helpers.release_is_active("EPEL 1") + assert not dashboard_helpers.release_is_active("Fedora 91") + assert not dashboard_helpers.release_is_active("EPEL 3") + + def test_release_from_dist(self, monkeypatch): + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + assert dashboard_helpers.release_from_dist("fc99") == "Fedora Rawhide" + assert dashboard_helpers.release_from_dist("fc98") == "Fedora 98" + assert dashboard_helpers.release_from_dist("f98") == "Fedora 98" + assert dashboard_helpers.release_from_dist("fc90") == "Fedora 90" + assert dashboard_helpers.release_from_dist("fc99s") == "Fedora Unknown" + + assert dashboard_helpers.release_from_dist("el1") == "EPEL 1" + assert dashboard_helpers.release_from_dist("epel1") == "EPEL 1" + assert dashboard_helpers.release_from_dist("el1~bootstrap") == "EPEL 1" + + def test_release_from_nevra(self, monkeypatch): + + app.config["EPEL_RELEASES"] = [1, 2] + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + assert dashboard_helpers.release_from_nvr("package-1.2.1-1.fc99") == "Fedora Rawhide" + assert dashboard_helpers.release_from_nvr("package-1:1.2.1-1.fc98") == "Fedora 98" + assert dashboard_helpers.release_from_nvr("package-2.2.1-1.fc16") == "Fedora 16" + assert dashboard_helpers.release_from_nvr("package-0.1.1-1.el1") == "EPEL 1" + assert dashboard_helpers.release_from_nvr("package-0.1.1-1.el2~bootstrap") == "EPEL 2" + + def test_release_from_number(self, monkeypatch): + + app.config["EPEL_RELEASES"] = [1, 2] + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + assert dashboard_helpers.release_from_number("99") == "Fedora Rawhide" + assert dashboard_helpers.release_from_number("rawhide") == "Fedora Rawhide" + assert dashboard_helpers.release_from_number("98") == "Fedora 98" + assert dashboard_helpers.release_from_number("90") == "Fedora 90" + assert dashboard_helpers.release_from_number("1") == "EPEL 1" + + def test_name_in_nevra(self, monkeypatch): + + assert dashboard_helpers.name_in_nevra("package", "package-1:1.2.1-1.fc98") + assert dashboard_helpers.name_in_nevra("package", "package-1.2.1-1.fc99") + assert dashboard_helpers.name_in_nevra("package-a", "package-a-1:1.2.1-1.el1.x86_64") + assert not dashboard_helpers.name_in_nevra("Package", "package-1:1.2.1-1.el2") + + def test_get_fedora_releases(self, monkeypatch): + + expected_result = { + 'branched': 98, + 'branched_frozen': True, + 'oldstable': 96, + 'rawhide': 99, + 'stable': 97, + 'values': [96, 97, 98, 99] + } + + monkeypatch.setattr(fedfind.helpers, 'get_current_stables', mock.MagicMock(return_value=[95,96,97])) + monkeypatch.setattr(fedfind.helpers, 'get_current_release', mock.MagicMock(return_value=98)) + monkeypatch.setattr(dashboard_helpers, 'branched_frozen', mock.MagicMock(return_value=True)) + assert dashboard_helpers.get_fedora_releases() == expected_result + + def test_branched_frozen(self, monkeypatch): + + yaml_response = "Frozen: True\n" + + monkeypatch.setattr(dashboard_helpers, 'get_json', mock.MagicMock(return_value=yaml_response)) + assert dashboard_helpers.branched_frozen() diff --git a/tests/test_packager_dashboard_koschei.py b/tests/test_packager_dashboard_koschei.py new file mode 100644 index 0000000..8aeb3f2 --- /dev/null +++ b/tests/test_packager_dashboard_koschei.py @@ -0,0 +1,121 @@ +import pytest +import mock + +from oraculum.utils import koschei +from oraculum import app, CACHE + +class MockedKoji(): + + def multiCall(): + # Koji returns only one build per release + stub_koji_element_a = [[{'tag_id': 2, 'tag_name': 'f98', 'id': 1, 'build_id': 1, 'version': '1.2.2', 'release': '2.fc98', 'epoch': None, 'state': 1, 'completion_time': '2020-01-28 11:08:00.940846+00:00', 'start_time': '2020-01-28 11:06:16.563830+00:00', 'task_id': 1, 'creation_event_id': 1, 'creation_time': '2020-01-28 11:06:16.563830+00:00', 'volume_id': 0, 'volume_name': 'DEFAULT', 'package_id': 1, 'package_name': 'package_a', 'name': 'package_a', 'nvr': 'package_a-1.2.2-2.fc99', 'owner_id': 1, 'owner_name': 'releng'}]] + + stub_koji_element_b = [[{'tag_id': 3, 'tag_name': 'f99', 'id': 2, 'build_id': 2, 'version': '1.2.2', 'release': '1.fc99', 'epoch': None, 'state': 1, 'completion_time': '2020-01-01 11:08:00.940846+00:00', 'start_time': '2020-01-01 11:06:16.563830+00:00', 'task_id': 1, 'creation_event_id': 1, 'creation_time': '2020-01-01 11:06:16.563830+00:00', 'volume_id': 0, 'volume_name': 'DEFAULT', 'package_id': 1, 'package_name': 'package_a', 'name': 'package_a', 'nvr': 'package_a-1.2.2-1.fc99', 'owner_id': 1, 'owner_name': 'releng'}]] + + return [stub_koji_element_a, stub_koji_element_b] + + +class TestKoschei(object): + + stub_fedora_releases = { + "oldstable": 96, + "stable": 97, + "branched": 98, + "rawhide": 99, + "values": [96, 97, 98, 99] + } + + koschei_result = { + 'package_a': [ + { + 'last_success': {'time': None, 'url': None}, + 'release': 'Fedora 98', + 'status': 'ok', + 'url': 'https://koschei.fedoraproject.org/package/package_a?collection=f98' + }, + { + 'last_success': {'time': None, 'url': None}, + 'release': 'Fedora Rawhide', + 'status': 'failing', + 'url': 'https://koschei.fedoraproject.org/package/package_a?collection=f99' + }, + { + 'last_success': {'time': None, 'url': None}, + 'release': 'EPEL 1', + 'status': 'ok', + 'url': 'https://koschei.fedoraproject.org/package/package_a?collection=epel1' + }, + { + 'last_success': {'time': None, 'url': None}, + 'release': 'EPEL 2', + 'status': 'blocked', + 'url': 'https://koschei.fedoraproject.org/package/package_a?collection=epel2' + } + ] + } + + def test_koschei_data(self, monkeypatch): + + stub_koschei_data = [ + { + "name":"package_a", + "collection":"f98", + "state":"ok", + "last_complete_build": + { + "task_id":1 + } + }, + { + "name":"package_a", + "collection":"f99", + "state":"failing", + "last_complete_build": + { + "task_id":2 + } + }, + { + "name":"package_a", + "collection":"epel1", + "state":"ok", + "last_complete_build": + { + "task_id":3 + } + }, + { + "name":"package_a", + "collection":"epel2", + "state":"blocked", + "last_complete_build": + { + "task_id":4 + } + } + ] + + + # Force EPEL Releases for tests + # This is usually defined in settings.py by real values, so we can't put it in config.py TEST block + app.config["EPEL_RELEASES"] = [1, 2] + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + monkeypatch.setattr(koschei, 'get_json', mock.MagicMock(return_value=stub_koschei_data)) + monkeypatch.setattr(koschei, 'koji', mock.MagicMock(return_value=True)) + assert koschei.parse_koschei_data() == self.koschei_result + + def test_koji_data(self, monkeypatch): + + expected_result = { + 'last_success': {'time': '2020-01-01 11:08:00.940846+00:00', 'url': 'https://koji.fedoraproject.org/koji/buildinfo?buildID=2'}, + 'release': 'Fedora Rawhide', + 'status': 'failing', + 'url': 'https://koschei.fedoraproject.org/package/package_a?collection=f99' + } + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=self.stub_fedora_releases)) + result = koschei.process_koji_queue(MockedKoji, self.koschei_result) + + assert len(result) == 1 + assert expected_result in result['package_a'] diff --git a/tests/test_packager_dashboard_orphans.py b/tests/test_packager_dashboard_orphans.py new file mode 100644 index 0000000..d32611f --- /dev/null +++ b/tests/test_packager_dashboard_orphans.py @@ -0,0 +1,91 @@ +import pytest +import mock + +from oraculum.utils import orphans + +class TestOrphans(object): + + + def test_orphans(self): + """ + * notes packages being orphaned + A -- B -- C* + -- D* -- E* + -- E* + -- F* + """ + DATA = { + "affected_packages": { + 'A': ['B', 'F'], + 'B': ['C', 'D', 'E'], + 'C': [], + 'D': ['E'], + 'E': [], + 'F': [] + }, + "status_change": { + 'C': '2020-01-01T00:00:00', + 'D': '2020-01-01T00:00:01', + 'E': '2020-01-01T00:00:02', + 'F': '2020-01-01T00:00:03', + + } + } + out = orphans.get_orphans(["A", "F", "Z"], DATA) + # Not affected + o_z = { + "orphaned": False, + "depends_on_orphaned": False, + "direct_dependencies": [], + "remote_dependencies": [], + "problematic_since": None, + "dot_graph": "", + "vis_js": {"nodes": [], "edges": []} + } + assert out["Z"] == o_z + + # Directly orphaned + o_f = { + "orphaned": True, + "depends_on_orphaned": False, + "direct_dependencies": [], + "remote_dependencies": [], + "problematic_since": '2020-01-01T00:00:03', + "dot_graph": "", + "vis_js": {"nodes": [], "edges": []} + } + assert out["F"] == o_f + + # Complete example + o_a = { + "orphaned": False, + "depends_on_orphaned": True, + "direct_dependencies": ['F'], + "remote_dependencies": ['C', 'D', 'E'], + "problematic_since": '2020-01-01T00:00:00' + } + dg = sorted(out["A"]["dot_graph"].split('\n')) + vis_js = out["A"]["vis_js"] + del(out["A"]["dot_graph"]) + del(out["A"]["vis_js"]) + + out["A"]["remote_dependencies"].sort() + assert out["A"] == o_a + + o_dg = sorted([ + '"A" -- "B" -- "C";', + '"A" -- "B" -- "D";', + '"A" -- "B" -- "E";', + '"A" -- "F";' + ]) + assert o_dg == dg + + assert len(vis_js.keys()) == 2 + assert 'nodes' in vis_js.keys() + assert 'edges' in vis_js.keys() + + nodes = sorted([(n['id'], n['label']) for n in vis_js['nodes']]) + assert nodes == [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E'), (5, 'F')] + + edges = sorted([(e['from'], e['to']) for e in vis_js['edges']]) + assert edges == [(0, 1), (0, 5), (1, 2), (1, 3), (1, 4)] diff --git a/tests/test_packager_dashboard_pagure.py b/tests/test_packager_dashboard_pagure.py new file mode 100644 index 0000000..5244254 --- /dev/null +++ b/tests/test_packager_dashboard_pagure.py @@ -0,0 +1,210 @@ +import pytest +import mock + +from oraculum.utils import pagure +from oraculum import app, CACHE + + +def stub_get_json_for_pagure_groups(url): + + stub_groups = { + "groups": [ + "group_not_to_be_included", + "included-cause-sig", + "sig-but-not-really", + "sssd-maintainers" + ] + } + + stub_group = { + "members": ["jdoe", "mr_packager"], + "projects": [ + { + "name": "glorious_package" + }, + { + "name": "some_other_package" + } + ] + } + + if "projects=1&acl=commit" in url: + return stub_group + return stub_groups + + +def stub_get_json_for_pagure_versions(url, *args): + + # Define data we're going to return + stub_pagure_versions_mdapi = { + "version": "80.0.1", + "release": "1.fc98" + } + + stub_pagure_versions_complete = { + "updates": { + "EL99": {"stable": None, "testing": None}, + "EL100": {"stable": None, "testing": None}, + "F96": {"stable": "package-80.0.1-1.fc96", "testing": "package-80.0.1-2.fc96"}, + "F97": {"stable": "package-80.0.1-1.fc97", "testing": "package-80.0.1-2.fc97"}, + "F98": {"stable": "package-80.0.1-1.fc98", "testing": "package-80.0.1-1.fc98"}, + "F99": {"stable": "package-80.0.1-1.fc98", "testing": "package-80.0.1-1.fc98"}, + } + } + + stub_pagure_versions_incomplete = { + "updates": { + "F96": {"stable": "package-80.0.1-1.fc96", "testing": "package-80.0.1-2.fc96"}, + "F97": {"stable": "package-80.0.1-1.fc97", "testing": "package-80.0.1-2.fc97"}, + "F98": {"stable": None, "testing": "package-80.0.1-1.fc98"}, + "F99": {"stable": None, "testing": "package-80.0.1-1.fc98"}, + } + } + + if "bodhi_updates" in url: + if "complete" in url: + return stub_pagure_versions_complete + else: + return stub_pagure_versions_incomplete + return stub_pagure_versions_mdapi + + +class TestPagure(object): + + + def test_package_prs(self, monkeypatch): + + stub_pagure_prs_data = { + "requests": [ + { + "id": 0, + "status": "Open", + "title": "Open PR Title", + "date_created": "1598478958", + "last_updated": "1568380289", + "branch": "master", + "user": { + "name": "John Doe" + }, + "comments": [{}, {}] + }, + { + "id": 1, + "status": "Closed", + "title": "Open PR Title", + "date_created": "1598478958", + "last_updated": "1568380289", + "branch": "master", + "user": { + "name": "John Doe" + }, + "comments": [{}, {}] + } + ] + } + + monkeypatch.setattr(pagure, 'get_json', mock.MagicMock(return_value=stub_pagure_prs_data)) + monkeypatch.setattr(pagure, 'get_pr_ci_result', mock.MagicMock(return_value=None)) + result = pagure.get_package_prs('testPackage') + assert len(result) == 1 + assert result[0]["author"] == "John Doe" + assert result[0]["release"] == "Fedora Rawhide" + + + def test_package_pr_cis(self, monkeypatch): + + stub_pagure_prs_cis_data = { + "flags": [ + { + "username": "simple-koji-ci", + "status": "failure" + }, + { + "username": "Zuul", + "status": "success" + }, + { + "username": "Zuul", + "status": "failure" + } + ] + } + + monkeypatch.setattr(pagure, 'get_json', mock.MagicMock(return_value=stub_pagure_prs_cis_data)) + result = pagure.get_pr_ci_result('testPackage', 0) + assert len(result) == 2 + assert result["Zuul"] == "success" + assert result["simple-koji-ci"] == "failure" + + + def test_pagure_groups(self, monkeypatch): + + stub_pkg_owners = { + "rpms": { + "directly_jdoes_package": ["jdoe", "somebody"], + "no_package": ["nobody"] + } + } + + expected_groups_result = { + "included-cause-sig": { + "users": ["jdoe", "mr_packager"], + "packages": ["glorious_package", "some_other_package"] + }, + "sssd-maintainers": { + "users": ["jdoe", "mr_packager"], + "packages": ["glorious_package", "some_other_package"] + } + } + + expected_user_group_result = { + "included-cause-sig": ["glorious_package", "some_other_package"], + "sssd-maintainers": ["glorious_package", "some_other_package"] + } + + monkeypatch.setattr(pagure, 'get_json', stub_get_json_for_pagure_groups) + result_groups = pagure.get_pagure_groups() + assert result_groups == expected_groups_result + + # let's test the rest of pagure groups functions + result_grp_pkgs = pagure.get_user_group_packages("jdoe", result_groups) + assert set(["glorious_package", "some_other_package"]) == result_grp_pkgs[1] + assert result_grp_pkgs[0] == expected_user_group_result + + result_complete = pagure.get_packages("jdoe", stub_pkg_owners, result_groups) + assert ["directly_jdoes_package"] == result_complete["primary"] + + assert "glorious_package" in result_complete["combined"] + assert "some_other_package" in result_complete["combined"] + assert "directly_jdoes_package" in result_complete["combined"] + + assert expected_user_group_result == result_complete["group"] + + + def test_pagure_versions(self, monkeypatch): + pagure_versions_result = { + "EPEL 1": {"stable": None, "testing": None}, + "EPEL 2": {"stable": None, "testing": None}, + "Fedora 96": {"stable": "package-80.0.1-1.fc96", "testing": "package-80.0.1-2.fc96"}, + "Fedora 97": {"stable": "package-80.0.1-1.fc97", "testing": "package-80.0.1-2.fc97"}, + "Fedora 98": {"stable": "package-80.0.1-1.fc98", "testing": "package-80.0.1-1.fc98"}, + "Fedora Rawhide": {"stable": "package-80.0.1-1.fc98", "testing": "package-80.0.1-1.fc98"} + } + + stub_fedora_releases = { + "oldstable": 96, + "stable": 97, + "branched": 98, + "rawhide": 99, + "values": [96, 97, 98, 99] + } + + # Force EPEL Releases for tests + # This is usually defined in settings.py by real values, so we can't put it in config.py TEST block + app.config["EPEL_RELEASES"] = [1, 2] + + monkeypatch.setattr(CACHE, 'get', mock.MagicMock(return_value=stub_fedora_releases)) + monkeypatch.setattr(pagure, 'get_json', stub_get_json_for_pagure_versions) + + assert pagure.get_package_versions("completePackage") == pagure_versions_result + assert pagure.get_package_versions("package") == pagure_versions_result diff --git a/tox.ini b/tox.ini index 74dfdec..56f681e 100644 --- a/tox.ini +++ b/tox.ini @@ -14,4 +14,13 @@ max-line-length=120 minversion=2.0 python_functions=test should python_files=test_* functest_* -addopts=--functional testing/ + +[tox] +# Let's not put here unreleased python versions that igraph doesn't come in pre-compiled form for +envlist = py38 + +[testenv] +deps = + pytest + mock +commands = pytest {posargs}