mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
* Updating idna (3.4 -> 3.6) * Updating annotated-types (0.5.0 -> 0.6.0) * Updating pydantic-core (2.10.1 -> 2.14.5) * Updating certifi (2023.7.22 -> 2023.11.17) * Updating greenlet (3.0.0 -> 3.0.1) * Updating pydantic (2.4.2 -> 2.5.2) * Updating charset-normalizer (3.3.0 -> 3.3.2) * Updating cryptography (41.0.4 -> 41.0.5) * Updating fastapi (0.103.2 -> 0.104.1) * Updating mako (1.2.4 -> 1.3.0) * Updating parse (1.19.1 -> 1.20.0) * Updating prometheus-client (0.17.1 -> 0.19.0) * Updating urllib3 (2.0.6 -> 2.1.0) Fix type annotation for new test function Signed-off-by: moson <moson@archlinux.org>
402 lines
13 KiB
Python
402 lines
13 KiB
Python
import re
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
import aurweb.filters # noqa: F401
|
|
from aurweb import config, db, templates, time
|
|
from aurweb.filters import as_timezone, number_format, timestamp_to_datetime as to_dt
|
|
from aurweb.models import Package, PackageBase, User
|
|
from aurweb.models.account_type import USER_ID
|
|
from aurweb.models.group import Group
|
|
from aurweb.models.license import License
|
|
from aurweb.models.package_base import popularity
|
|
from aurweb.models.package_group import PackageGroup
|
|
from aurweb.models.package_license import PackageLicense
|
|
from aurweb.models.package_relation import PackageRelation
|
|
from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID
|
|
from aurweb.templates import (
|
|
base_template,
|
|
make_context,
|
|
make_variable_context,
|
|
register_filter,
|
|
register_function,
|
|
)
|
|
from aurweb.testing.html import parse_root
|
|
from aurweb.testing.requests import Request
|
|
|
|
GIT_CLONE_URI_ANON = "anon_%s"
|
|
GIT_CLONE_URI_PRIV = "priv_%s"
|
|
|
|
|
|
@register_filter("func")
|
|
def func():
|
|
pass
|
|
|
|
|
|
@register_function("function")
|
|
def function():
|
|
pass
|
|
|
|
|
|
def create_user(username: str) -> User:
|
|
with db.begin():
|
|
user = db.create(
|
|
User,
|
|
Username=username,
|
|
Email=f"{username}@example.org",
|
|
Passwd="testPassword",
|
|
AccountTypeID=USER_ID,
|
|
)
|
|
return user
|
|
|
|
|
|
def create_pkgrel(package: Package, reltype_id: int, relname: str) -> PackageRelation:
|
|
return db.create(
|
|
PackageRelation, Package=package, RelTypeID=reltype_id, RelName=relname
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def user(db_test) -> User:
|
|
user = create_user("test")
|
|
yield user
|
|
|
|
|
|
@pytest.fixture
|
|
def pkgbase(user: User) -> PackageBase:
|
|
now = time.utcnow()
|
|
with db.begin():
|
|
pkgbase = db.create(
|
|
PackageBase,
|
|
Name="test-pkg",
|
|
Maintainer=user,
|
|
SubmittedTS=now,
|
|
ModifiedTS=now,
|
|
)
|
|
yield pkgbase
|
|
|
|
|
|
@pytest.fixture
|
|
def package(user: User, pkgbase: PackageBase) -> Package:
|
|
with db.begin():
|
|
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
|
|
yield pkg
|
|
|
|
|
|
def create_license(pkg: Package, license_name: str) -> PackageLicense:
|
|
lic = db.create(License, Name=license_name)
|
|
pkglic = db.create(PackageLicense, License=lic, Package=pkg)
|
|
return pkglic
|
|
|
|
|
|
def create_group(pkg: Package, group_name: str) -> PackageGroup:
|
|
grp = db.create(Group, Name=group_name)
|
|
pkggrp = db.create(PackageGroup, Group=grp, Package=pkg)
|
|
return pkggrp
|
|
|
|
|
|
def test_register_function_exists_key_error():
|
|
"""Most instances of register_filter are tested through module
|
|
imports or template renders, so we only test failures here."""
|
|
with pytest.raises(KeyError):
|
|
|
|
@register_function("function")
|
|
def some_func():
|
|
pass
|
|
|
|
|
|
def test_commit_hash():
|
|
# Hashes we'll use for this test. long_commit_hash should be
|
|
# shortened to commit_hash for rendering.
|
|
commit_hash = "abcdefg"
|
|
long_commit_hash = commit_hash + "1234567"
|
|
|
|
def config_get_with_fallback(
|
|
section: str, option: str, fallback: str = None
|
|
) -> str:
|
|
if section == "devel" and option == "commit_hash":
|
|
return long_commit_hash
|
|
return config.original_get_with_fallback(section, option, fallback)
|
|
|
|
# Fake config.get_with_fallback.
|
|
config.original_get_with_fallback = config.get_with_fallback
|
|
config.get_with_fallback = config_get_with_fallback
|
|
|
|
request = Request()
|
|
context = templates.make_context(request, "Test Context")
|
|
render = templates.render_raw_template(request, "index.html", context)
|
|
|
|
# We've faked config.get_with_fallback to return a "valid" commit_hash
|
|
# when queried. Test that the expected render occurs.
|
|
commit_url = config.get("devel", "commit_url")
|
|
expected = commit_url % commit_hash
|
|
assert expected in render
|
|
assert f"HEAD@{commit_hash}" in render
|
|
assert long_commit_hash not in render
|
|
|
|
# Restore config.get_with_fallback.
|
|
config.get_with_fallback = config.original_get_with_fallback
|
|
config.original_get_with_fallback = None
|
|
|
|
# Now, we no longer fake the commit_hash option: no commit
|
|
# is displayed in the footer. Assert this expectation.
|
|
context = templates.make_context(request, "Test Context")
|
|
render = templates.render_raw_template(request, "index.html", context)
|
|
assert commit_hash not in render
|
|
|
|
|
|
def pager_context(num_packages: int) -> dict[str, Any]:
|
|
return {
|
|
"request": Request(),
|
|
"singular": "%d package found.",
|
|
"plural": "%d packages found.",
|
|
"prefix": "/packages",
|
|
"total": num_packages,
|
|
"O": 0,
|
|
"PP": 50,
|
|
}
|
|
|
|
|
|
def test_pager_no_results():
|
|
"""Test the pager partial with no results."""
|
|
num_packages = 0
|
|
context = pager_context(num_packages)
|
|
body = base_template("partials/pager.html").render(context)
|
|
|
|
root = parse_root(body)
|
|
stats = root.xpath('//div[@class="pkglist-stats"]/p')
|
|
expected = "0 packages found."
|
|
assert stats[0].text.strip() == expected
|
|
|
|
|
|
def test_pager():
|
|
"""Test the pager partial with two pages of results."""
|
|
num_packages = 100
|
|
context = pager_context(num_packages)
|
|
body = base_template("partials/pager.html").render(context)
|
|
|
|
root = parse_root(body)
|
|
stats = root.xpath('//div[@class="pkglist-stats"]/p')
|
|
stats = re.sub(r"\s{2,}", " ", stats[0].text.strip())
|
|
expected = f"{num_packages} packages found. Page 1 of 2."
|
|
assert stats == expected
|
|
|
|
|
|
def check_package_details(content: str, pkg: Package) -> None:
|
|
"""
|
|
Perform assertion checks against package details.
|
|
"""
|
|
pkgbase = pkg.PackageBase
|
|
|
|
root = parse_root(content)
|
|
pkginfo = root.xpath('//table[@id="pkginfo"]')[0]
|
|
rows = pkginfo.xpath("./tr")
|
|
|
|
# Check Git Clone URL.
|
|
git_clone_uris = rows[0].xpath("./td/a")
|
|
anon_uri, priv_uri = git_clone_uris
|
|
pkgbasename = pkgbase.Name
|
|
assert anon_uri.text.strip() == GIT_CLONE_URI_ANON % pkgbasename
|
|
assert priv_uri.text.strip() == GIT_CLONE_URI_PRIV % pkgbasename
|
|
|
|
# Check Package Base.
|
|
pkgbase_markup = rows[1].xpath("./td/a")[0]
|
|
assert pkgbase_markup.text.strip() == pkgbasename
|
|
|
|
# Check Description.
|
|
desc = rows[2].xpath("./td")[0]
|
|
assert desc.text.strip() == str(pkg.Description)
|
|
|
|
# Check URL, for which we have none. In this case, no <a> should
|
|
# be used since we have nothing to link.
|
|
url = rows[3].xpath("./td")[0]
|
|
assert url.text.strip() == str(pkg.URL)
|
|
|
|
# Check Keywords, which should be empty.
|
|
keywords = rows[4].xpath("./td/form/div/input")[0]
|
|
assert keywords.attrib["value"] == str()
|
|
|
|
i = 4
|
|
licenses = pkg.package_licenses.all()
|
|
if licenses:
|
|
i += 1
|
|
expected = ", ".join([p.License.Name for p in licenses])
|
|
license_markup = rows[i].xpath("./td")[0]
|
|
assert license_markup.text.strip() == expected
|
|
else:
|
|
assert "Licenses" not in content
|
|
|
|
groups = pkg.package_groups.all()
|
|
if groups:
|
|
i += 1
|
|
expected = ", ".join([p.Group.Name for p in groups])
|
|
group_markup = rows[i].xpath("./td")[0]
|
|
assert group_markup.text.strip() == expected
|
|
else:
|
|
assert "Groups" not in content
|
|
|
|
provides = pkg.package_relations.filter(
|
|
PackageRelation.RelTypeID == PROVIDES_ID
|
|
).all()
|
|
if provides:
|
|
i += 1
|
|
expected = ", ".join([p.RelName for p in provides])
|
|
provides_markup = rows[i].xpath("./td")[0]
|
|
assert provides_markup.text.strip() == expected
|
|
else:
|
|
assert "Provides" not in content
|
|
|
|
replaces = pkg.package_relations.filter(
|
|
PackageRelation.RelTypeID == REPLACES_ID
|
|
).all()
|
|
if replaces:
|
|
i += 1
|
|
expected = ", ".join([r.RelName for r in replaces])
|
|
replaces_markup = rows[i].xpath("./td")[0]
|
|
assert replaces_markup.text.strip() == expected
|
|
else:
|
|
assert "Replaces" not in content
|
|
|
|
# Check Submitter.
|
|
selector = "./td" if not pkg.PackageBase.Submitter else "./td/a"
|
|
i += 1
|
|
submitter = rows[i].xpath(selector)[0]
|
|
assert submitter.text.strip() == str(pkg.PackageBase.Submitter)
|
|
|
|
# Check Maintainer.
|
|
selector = "./td" if not pkg.PackageBase.Maintainer else "./td/a"
|
|
i += 1
|
|
maintainer = rows[i].xpath(selector)[0]
|
|
assert maintainer.text.strip() == str(pkg.PackageBase.Maintainer)
|
|
|
|
# Check Packager.
|
|
selector = "./td" if not pkg.PackageBase.Packager else "./td/a"
|
|
i += 1
|
|
packager = rows[i].xpath(selector)[0]
|
|
assert packager.text.strip() == str(pkg.PackageBase.Packager)
|
|
|
|
# Check Votes.
|
|
i += 1
|
|
votes = rows[i].xpath("./td")[0]
|
|
assert votes.text.strip() == str(pkg.PackageBase.NumVotes)
|
|
|
|
# Check Popularity; for this package, a number_format of 6 places is used.
|
|
i += 1
|
|
pop = rows[i].xpath("./td")[0]
|
|
assert pop.text.strip() == number_format(0, 6)
|
|
|
|
# Check First Submitted
|
|
date_fmt = "%Y-%m-%d %H:%M (%Z)"
|
|
i += 1
|
|
first_submitted = rows[i].xpath("./td")[0]
|
|
converted_dt = as_timezone(to_dt(pkg.PackageBase.SubmittedTS), "UTC")
|
|
expected = converted_dt.strftime(date_fmt)
|
|
assert first_submitted.text.strip() == expected
|
|
|
|
# Check Last Updated.
|
|
i += 1
|
|
last_updated = rows[i].xpath("./td")[0]
|
|
converted_dt = as_timezone(to_dt(pkg.PackageBase.ModifiedTS), "UTC")
|
|
expected = converted_dt.strftime(date_fmt)
|
|
assert last_updated.text.strip() == expected
|
|
|
|
|
|
def test_package_details(user: User, package: Package):
|
|
"""Test package details with most fields populated, but not all."""
|
|
request = Request(user=user, authenticated=True)
|
|
context = make_context(request, "Test Details")
|
|
|
|
context.update(
|
|
{
|
|
"request": request,
|
|
"git_clone_uri_anon": GIT_CLONE_URI_ANON,
|
|
"git_clone_uri_priv": GIT_CLONE_URI_PRIV,
|
|
"pkgbase": package.PackageBase,
|
|
"popularity": popularity(package.PackageBase, time.utcnow()),
|
|
"package": package,
|
|
"comaintainers": [],
|
|
}
|
|
)
|
|
|
|
base = base_template("partials/packages/details.html")
|
|
body = base.render(context, show_package_details=True)
|
|
check_package_details(body, package)
|
|
|
|
|
|
def test_package_details_filled(user: User, package: Package):
|
|
"""Test package details with all fields populated."""
|
|
|
|
pkgbase = package.PackageBase
|
|
with db.begin():
|
|
# Setup Submitter and Packager; Maintainer is already set to `user`.
|
|
pkgbase.Submitter = pkgbase.Packager = user
|
|
|
|
# Create two licenses.
|
|
create_license(package, "TPL") # Testing Public License
|
|
create_license(package, "TPL2") # Testing Public License 2
|
|
|
|
# Create two groups.
|
|
create_group(package, "GRP")
|
|
create_group(package, "GRP2")
|
|
|
|
# Add provides.
|
|
create_pkgrel(package, PROVIDES_ID, "test-provider")
|
|
|
|
# Add replaces.
|
|
create_pkgrel(package, REPLACES_ID, "test-replacement")
|
|
|
|
request = Request(user=user, authenticated=True)
|
|
context = make_context(request, "Test Details")
|
|
context.update(
|
|
{
|
|
"request": request,
|
|
"git_clone_uri_anon": GIT_CLONE_URI_ANON,
|
|
"git_clone_uri_priv": GIT_CLONE_URI_PRIV,
|
|
"pkgbase": package.PackageBase,
|
|
"popularity": popularity(package.PackageBase, time.utcnow()),
|
|
"package": package,
|
|
"comaintainers": [],
|
|
"licenses": package.package_licenses,
|
|
"groups": package.package_groups,
|
|
"provides": package.package_relations.filter(
|
|
PackageRelation.RelTypeID == PROVIDES_ID
|
|
),
|
|
"replaces": package.package_relations.filter(
|
|
PackageRelation.RelTypeID == REPLACES_ID
|
|
),
|
|
}
|
|
)
|
|
|
|
base = base_template("partials/packages/details.html")
|
|
body = base.render(context, show_package_details=True)
|
|
check_package_details(body, package)
|
|
|
|
|
|
def test_make_context_timezone(user: User, package: Package):
|
|
request = Request(
|
|
user=user, authenticated=True, url="/packages/test?timezone=foobar"
|
|
)
|
|
context = make_context(request, "Test Details")
|
|
assert context["timezone"] in time.SUPPORTED_TIMEZONES
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_make_variable_context_timezone(user: User, package: Package):
|
|
request = Request(
|
|
user=user, authenticated=True, url="/packages/test?timezone=foobar"
|
|
)
|
|
context = await make_variable_context(
|
|
request, "Test Details", next="/packages/test"
|
|
)
|
|
assert context["timezone"] in time.SUPPORTED_TIMEZONES
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_make_variable_context_params():
|
|
request = Request(url="/test", query_params={"request": "test", "x": "test"})
|
|
context = await make_variable_context(request, "Test")
|
|
|
|
# make sure we can't override our Request object with a query parameter
|
|
assert context["request"] != "test"
|
|
assert context["x"] == "test"
|