blob: b5aeac6d655c8570f3f26b4ccfc74bcf4b86ad8f [file]
"""Tests for the admin user search, archive and default-branch endpoints"""
import asyncio
import types
import asfpy.messaging
import pytest
import endpoints.archive
import endpoints.defaultbranch
import endpoints.users
import plugins.configuration
import plugins.github
import plugins.projects
import plugins.session
class FakeServer:
def __init__(self):
self.data = plugins.configuration.InterData()
self.config = types.SimpleNamespace(
github=types.SimpleNamespace(org="apache", token="x" * 40)
)
def make_session(uid="humbedooh", admin=False, logged_in=True):
session = plugins.session.SessionObject.__new__(plugins.session.SessionObject)
if logged_in:
session.credentials = plugins.session.SessionCredentials(
uid=uid, admin=admin, name="Humbe Dooh", email=f"{uid}@apache.org"
)
else:
session.credentials = None
return session
def make_person(asf_id, github_login=None, mfa=False):
person = plugins.projects.Committer(asf_id, None)
person.github_login = github_login
person.github_mfa = mfa
return person
class FakeRepo:
def __init__(self, filename, filepath):
self.filename = filename
self.filepath = filepath
def stub_github_org(monkeypatch, fail=False):
"""Replaces the GitHub org with one that records PATCH calls instead of making them"""
patched = []
class FakeOrg:
def __init__(self, login="", personal_access_token=""):
self.login = login
async def get_id(self):
return 1
async def api_patch(self, url, jsdata=None):
if fail:
raise AssertionError("GitHub said no")
patched.append((url, jsdata))
monkeypatch.setattr(plugins.github, "GitHubOrganisation", FakeOrg)
return patched
def test_user_search_requires_admin_access():
server = FakeServer()
rv = asyncio.run(endpoints.users.process(server, make_session(), {"query": "humbedooh"}))
assert rv["okay"] is False
def test_user_search_matches_asf_ids_and_github_logins():
server = FakeServer()
server.data.people = [make_person("humbedooh", "gh-humbedooh"), make_person("gstein", "gh-gstein")]
session = make_session(admin=True)
by_asf = asyncio.run(endpoints.users.process(server, session, {"query": "humbe"}))
assert [x["asf_id"] for x in by_asf["results"]] == ["humbedooh"]
by_github = asyncio.run(endpoints.users.process(server, session, {"query": "gh-gstein"}))
assert [x["asf_id"] for x in by_github["results"]] == ["gstein"]
def test_user_search_reports_link_and_invite_status():
server = FakeServer()
server.data.people = [make_person("humbedooh", "gh-humbedooh", mfa=True)]
server.data.mfa = {"gh-humbedooh": True}
rv = asyncio.run(endpoints.users.process(server, make_session(admin=True), {"query": "humbedooh"}))
result = rv["results"][0]
assert result["github_id"] == "gh-humbedooh"
assert result["github_mfa"] is True
assert result["github_invited"] is True
def test_user_search_without_a_query_returns_nothing():
server = FakeServer()
server.data.people = [make_person("humbedooh", "gh-humbedooh")]
rv = asyncio.run(endpoints.users.process(server, make_session(admin=True), {}))
assert rv == {"okay": True, "results": []}
def test_user_search_caps_the_result_count():
server = FakeServer()
server.data.people = [make_person(f"user{i:02}") for i in range(20)]
rv = asyncio.run(endpoints.users.process(server, make_session(admin=True), {"query": "user"}))
# The break only fires after the 11th append, so the cap is 11, not 10
assert len(rv["results"]) == 11
def test_archive_requires_admin_access(monkeypatch):
server = FakeServer()
rv = asyncio.run(endpoints.archive.process(server, make_session(), {"repository": "httpd"}))
assert rv["okay"] is False
def test_archive_rejects_unknown_repositories(monkeypatch):
server = FakeServer()
rv = asyncio.run(
endpoints.archive.process(server, make_session(admin=True), {"repository": "ghost"})
)
assert rv["okay"] is False
def test_archive_flags_the_repo_on_github_and_gitbox(monkeypatch, tmp_path):
patched = stub_github_org(monkeypatch)
server = FakeServer()
repo_dir = tmp_path / "httpd.git"
repo_dir.mkdir()
server.data.repositories = [FakeRepo("httpd", str(repo_dir))]
rv = asyncio.run(
endpoints.archive.process(server, make_session(admin=True), {"repository": "httpd"})
)
assert rv["okay"] is True
assert patched == [("https://api.github.com/repos/apache/httpd", {"archived": True})]
nocommit = (repo_dir / "nocommit").read_text()
assert "humbedooh" in nocommit
def test_archive_leaves_gitbox_alone_when_github_fails(monkeypatch, tmp_path):
"""Half-archiving would leave GitHub writable while GitBox rejects pushes, or vice versa"""
stub_github_org(monkeypatch, fail=True)
server = FakeServer()
repo_dir = tmp_path / "httpd.git"
repo_dir.mkdir()
server.data.repositories = [FakeRepo("httpd", str(repo_dir))]
rv = asyncio.run(
endpoints.archive.process(server, make_session(admin=True), {"repository": "httpd"})
)
assert rv["okay"] is False
assert not (repo_dir / "nocommit").exists()
def test_default_branch_requires_a_login():
server = FakeServer()
rv = asyncio.run(
endpoints.defaultbranch.process(server, make_session(logged_in=False), {"default_branch": "main"})
)
assert rv["okay"] is False
def test_default_branch_requires_a_branch_name():
server = FakeServer()
rv = asyncio.run(endpoints.defaultbranch.process(server, make_session(), {"repository": "httpd"}))
assert rv["okay"] is False
def test_default_branch_rejects_unknown_repositories():
server = FakeServer()
rv = asyncio.run(
endpoints.defaultbranch.process(
server, make_session(), {"repository": "ghost", "default_branch": "main"}
)
)
assert rv["okay"] is False
def test_default_branch_updates_github_and_the_gitbox_head(monkeypatch, tmp_path):
patched = stub_github_org(monkeypatch)
mails = []
monkeypatch.setattr(asfpy.messaging, "mail", lambda **kwargs: mails.append(kwargs))
server = FakeServer()
repo_dir = tmp_path / "httpd.git"
repo_dir.mkdir()
server.data.repositories = [FakeRepo("httpd", str(repo_dir))]
rv = asyncio.run(
endpoints.defaultbranch.process(
server, make_session(admin=True), {"repository": "httpd", "default_branch": "main"}
)
)
assert rv["okay"] is True
assert patched == [("https://api.github.com/repos/apache/httpd", {"default_branch": "main"})]
assert (repo_dir / "HEAD").read_text() == "ref: refs/heads/main"
assert mails and mails[0]["recipients"] == ["private@httpd.apache.org"]