aurweb/test/test_templates.py
Kevin Morris 25e05830a6
test: test that /packages/{name} produces the package's description
This commit fixes two of our tests in test_templates.py to go along
with our new template modifications, as well as a new test in
test_packages_routes.py which constructs two packages belonging
to the same package base, then tests that viewing their pages
produces their independent descriptions.

Signed-off-by: Kevin Morris <kevr@0cost.org>
2022-09-05 19:50:41 -07:00

346 lines
11 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.license import License
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,
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 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
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,
"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
# 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,
"package": package,
"comaintainers": [],
"licenses": package.package_licenses,
"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)