style: Run pre-commit

This commit is contained in:
Joakim Saario 2022-08-21 22:08:29 +02:00
parent b47882b114
commit 9c6c13b78a
No known key found for this signature in database
GPG key ID: D8B76D271B7BD453
235 changed files with 7180 additions and 5628 deletions

View file

@ -39,12 +39,10 @@ ahead of each function takes too long when compared to this method.
"""
import os
import pathlib
from multiprocessing import Lock
import py
import pytest
from posix_ipc import O_CREAT, Semaphore
from sqlalchemy import create_engine
from sqlalchemy.engine import URL
@ -54,7 +52,6 @@ from sqlalchemy.orm import scoped_session
import aurweb.config
import aurweb.db
from aurweb import initdb, logging, testing
from aurweb.testing.email import Email
from aurweb.testing.filelock import FileLock
@ -78,13 +75,10 @@ def test_engine() -> Engine:
unix_socket = aurweb.config.get_with_fallback("database", "socket", None)
kwargs = {
"username": aurweb.config.get("database", "user"),
"password": aurweb.config.get_with_fallback(
"database", "password", None),
"password": aurweb.config.get_with_fallback("database", "password", None),
"host": aurweb.config.get("database", "host"),
"port": aurweb.config.get_with_fallback("database", "port", None),
"query": {
"unix_socket": unix_socket
}
"query": {"unix_socket": unix_socket},
}
backend = aurweb.config.get("database", "backend")
@ -99,6 +93,7 @@ class AlembicArgs:
This structure is needed to pass conftest-specific arguments
to initdb.run duration database creation.
"""
verbose = False
use_alembic = True
@ -156,7 +151,7 @@ def setup_email():
@pytest.fixture(scope="module")
def setup_database(tmp_path_factory: pathlib.Path, worker_id: str) -> None:
""" Create and drop a database for the suite this fixture is used in. """
"""Create and drop a database for the suite this fixture is used in."""
engine = test_engine()
dbname = aurweb.db.name()

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -17,17 +16,21 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def term() -> Term:
with db.begin():
term = db.create(Term, Description="Test term",
URL="https://test.term")
term = db.create(Term, Description="Test term", URL="https://test.term")
yield term

View file

@ -22,26 +22,30 @@ def account_type() -> AccountType:
def test_account_type(account_type):
""" Test creating an AccountType, and reading its columns. """
"""Test creating an AccountType, and reading its columns."""
# Make sure it got db.created and was given an ID.
assert bool(account_type.ID)
# Next, test our string functions.
assert str(account_type) == "TestUser"
assert repr(account_type) == \
"<AccountType(ID='%s', AccountType='TestUser')>" % (
account_type.ID)
assert repr(account_type) == "<AccountType(ID='%s', AccountType='TestUser')>" % (
account_type.ID
)
record = db.query(AccountType,
AccountType.AccountType == "TestUser").first()
record = db.query(AccountType, AccountType.AccountType == "TestUser").first()
assert account_type == record
def test_user_account_type_relationship(account_type):
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountType=account_type)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountType=account_type,
)
assert user.AccountType == account_type

File diff suppressed because it is too large Load diff

View file

@ -3,16 +3,17 @@ from unittest import mock
import pytest
import aurweb.models.account_type as at
from aurweb import db
from aurweb.models import User
from aurweb.scripts import adduser
from aurweb.testing.requests import Request
TEST_SSH_PUBKEY = ("ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAI"
"bmlzdHAyNTYAAABBBEURnkiY6JoLyqDE8Li1XuAW+LHmkmLDMW/GL5wY"
"7k4/A+Ta7bjA3MOKrF9j4EuUTvCuNXULxvpfSqheTFWZc+g= "
"kevr@volcano")
TEST_SSH_PUBKEY = (
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAI"
"bmlzdHAyNTYAAABBBEURnkiY6JoLyqDE8Li1XuAW+LHmkmLDMW/GL5wY"
"7k4/A+Ta7bjA3MOKrF9j4EuUTvCuNXULxvpfSqheTFWZc+g= "
"kevr@volcano"
)
@pytest.fixture(autouse=True)
@ -38,18 +39,36 @@ def test_adduser():
def test_adduser_tu():
run_main([
"-u", "test", "-e", "test@example.org", "-p", "abcd1234",
"-t", at.TRUSTED_USER
])
run_main(
[
"-u",
"test",
"-e",
"test@example.org",
"-p",
"abcd1234",
"-t",
at.TRUSTED_USER,
]
)
test = db.query(User).filter(User.Username == "test").first()
assert test is not None
assert test.AccountTypeID == at.TRUSTED_USER_ID
def test_adduser_ssh_pk():
run_main(["-u", "test", "-e", "test@example.org", "-p", "abcd1234",
"--ssh-pubkey", TEST_SSH_PUBKEY])
run_main(
[
"-u",
"test",
"-e",
"test@example.org",
"-p",
"abcd1234",
"--ssh-pubkey",
TEST_SSH_PUBKEY,
]
)
test = db.query(User).filter(User.Username == "test").first()
assert test is not None
assert TEST_SSH_PUBKEY.startswith(test.ssh_pub_keys.first().PubKey)

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -13,8 +12,7 @@ def setup(db_test):
def test_api_rate_key_creation():
with db.begin():
rate = db.create(ApiRateLimit, IP="127.0.0.1", Requests=10,
WindowStart=1)
rate = db.create(ApiRateLimit, IP="127.0.0.1", Requests=10, WindowStart=1)
assert rate.IP == "127.0.0.1"
assert rate.Requests == 10
assert rate.WindowStart == 1

View file

@ -1,20 +1,17 @@
import http
import os
import re
from typing import Callable
from unittest import mock
import fastapi
import pytest
from fastapi import HTTPException
from fastapi.testclient import TestClient
import aurweb.asgi
import aurweb.config
import aurweb.redis
from aurweb.exceptions import handle_form_exceptions
from aurweb.testing.requests import Request
@ -33,7 +30,9 @@ def mock_glab_request(monkeypatch):
if side_effect:
return side_effect # pragma: no cover
return return_value
monkeypatch.setattr("requests.post", what_to_return)
return wrapped
@ -47,13 +46,14 @@ def mock_glab_config(project: str = "test/project", token: str = "test-token"):
elif key == "error-token":
return token
return config_get(section, key)
return wrapper
@pytest.mark.asyncio
async def test_asgi_startup_session_secret_exception(monkeypatch):
""" Test that we get an IOError on app_startup when we cannot
connect to options.redis_address. """
"""Test that we get an IOError on app_startup when we cannot
connect to options.redis_address."""
redis_addr = aurweb.config.get("options", "redis_address")
@ -110,8 +110,9 @@ async def test_asgi_app_disabled_metrics(caplog: pytest.LogCaptureFixture):
with mock.patch.dict(os.environ, env):
await aurweb.asgi.app_startup()
expected = ("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics "
"endpoint is disabled.")
expected = (
"$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " "endpoint is disabled."
)
assert expected in caplog.text
@ -134,9 +135,12 @@ class FakeResponse:
self.text = text
def test_internal_server_error_bad_glab(setup: None, use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture):
def test_internal_server_error_bad_glab(
setup: None,
use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture,
):
@aurweb.asgi.app.get("/internal_server_error")
async def internal_server_error(request: fastapi.Request):
raise ValueError("test exception")
@ -154,9 +158,12 @@ def test_internal_server_error_bad_glab(setup: None, use_traceback: None,
assert re.search(expr, caplog.text)
def test_internal_server_error_no_token(setup: None, use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture):
def test_internal_server_error_no_token(
setup: None,
use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture,
):
@aurweb.asgi.app.get("/internal_server_error")
async def internal_server_error(request: fastapi.Request):
raise ValueError("test exception")
@ -175,9 +182,12 @@ def test_internal_server_error_no_token(setup: None, use_traceback: None,
assert re.search(expr, caplog.text)
def test_internal_server_error(setup: None, use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture):
def test_internal_server_error(
setup: None,
use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture,
):
@aurweb.asgi.app.get("/internal_server_error")
async def internal_server_error(request: fastapi.Request):
raise ValueError("test exception")
@ -203,9 +213,12 @@ def test_internal_server_error(setup: None, use_traceback: None,
assert "FATAL" not in caplog.text
def test_internal_server_error_post(setup: None, use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture):
def test_internal_server_error_post(
setup: None,
use_traceback: None,
mock_glab_request: Callable,
caplog: pytest.LogCaptureFixture,
):
@aurweb.asgi.app.post("/internal_server_error")
@handle_form_exceptions
async def internal_server_error(request: fastapi.Request):

View file

@ -1,5 +1,4 @@
import tempfile
from unittest import mock
import py
@ -32,7 +31,7 @@ def setup(db_test, alpm_db: AlpmDatabase, tempdir: py.path.local) -> None:
if key == "db-path":
return alpm_db.local
elif key == "server":
return f'file://{alpm_db.remote}'
return f"file://{alpm_db.remote}"
elif key == "sync-dbs":
return alpm_db.repo
return value
@ -51,8 +50,7 @@ def test_aurblup(alpm_db: AlpmDatabase):
# Test that the package got added to the database.
for name in ("pkg", "pkg2"):
pkg = db.query(OfficialProvider).filter(
OfficialProvider.Name == name).first()
pkg = db.query(OfficialProvider).filter(OfficialProvider.Name == name).first()
assert pkg is not None
# Test that we can remove the package.
@ -62,11 +60,9 @@ def test_aurblup(alpm_db: AlpmDatabase):
aurblup.main(True)
# Expect that the database got updated accordingly.
pkg = db.query(OfficialProvider).filter(
OfficialProvider.Name == "pkg").first()
pkg = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg").first()
assert pkg is None
pkg2 = db.query(OfficialProvider).filter(
OfficialProvider.Name == "pkg2").first()
pkg2 = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg2").first()
assert pkg2 is not None
@ -78,14 +74,16 @@ def test_aurblup_cleanup(alpm_db: AlpmDatabase):
# Now, let's insert an OfficialPackage that doesn't exist,
# then exercise the old provider deletion path.
with db.begin():
db.create(OfficialProvider, Name="fake package",
Repo="test", Provides="package")
db.create(
OfficialProvider, Name="fake package", Repo="test", Provides="package"
)
# Run aurblup again.
aurblup.main()
# Expect that the fake package got deleted because it's
# not in alpm_db anymore.
providers = db.query(OfficialProvider).filter(
OfficialProvider.Name == "fake package").all()
providers = (
db.query(OfficialProvider).filter(OfficialProvider.Name == "fake package").all()
)
assert len(providers) == 0

View file

@ -1,11 +1,15 @@
import fastapi
import pytest
from fastapi import HTTPException
from sqlalchemy.exc import IntegrityError
from aurweb import config, db, time
from aurweb.auth import AnonymousUser, BasicAuthBackend, _auth_required, account_type_required
from aurweb.auth import (
AnonymousUser,
BasicAuthBackend,
_auth_required,
account_type_required,
)
from aurweb.models.account_type import USER, USER_ID
from aurweb.models.session import Session
from aurweb.models.user import User
@ -20,9 +24,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.com",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.com",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -55,8 +64,7 @@ async def test_auth_backend_invalid_user_id():
# Create a new session with a fake user id.
now_ts = time.utcnow()
with pytest.raises(IntegrityError):
Session(UsersID=666, SessionID="realSession",
LastUpdateTS=now_ts + 5)
Session(UsersID=666, SessionID="realSession", LastUpdateTS=now_ts + 5)
@pytest.mark.asyncio
@ -65,8 +73,9 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend):
# equal the real_user.
now_ts = time.utcnow()
with db.begin():
db.create(Session, UsersID=user.ID, SessionID="realSession",
LastUpdateTS=now_ts + 5)
db.create(
Session, UsersID=user.ID, SessionID="realSession", LastUpdateTS=now_ts + 5
)
request = Request()
request.cookies["AURSID"] = "realSession"
@ -76,7 +85,7 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend):
@pytest.mark.asyncio
async def test_expired_session(backend: BasicAuthBackend, user: User):
""" Login, expire the session manually, then authenticate. """
"""Login, expire the session manually, then authenticate."""
# First, build a Request with a logged in user.
request = Request()
request.user = user
@ -115,8 +124,8 @@ async def test_auth_required_redirection_bad_referrer():
def test_account_type_required():
""" This test merely asserts that a few different paths
do not raise exceptions. """
"""This test merely asserts that a few different paths
do not raise exceptions."""
# This one shouldn't raise.
account_type_required({USER})
@ -125,7 +134,7 @@ def test_account_type_required():
# But this one should! We have no "FAKE" key.
with pytest.raises(KeyError):
account_type_required({'FAKE'})
account_type_required({"FAKE"})
def test_is_trusted_user():

View file

@ -1,14 +1,11 @@
import re
from http import HTTPStatus
from unittest import mock
import pytest
from fastapi.testclient import TestClient
import aurweb.config
from aurweb import db, time
from aurweb.asgi import app
from aurweb.models.account_type import USER_ID
@ -42,39 +39,41 @@ def client() -> TestClient:
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username=TEST_USERNAME, Email=TEST_EMAIL,
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username=TEST_USERNAME,
Email=TEST_EMAIL,
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
def test_login_logout(client: TestClient, user: User):
post_data = {
"user": "test",
"passwd": "testPassword",
"next": "/"
}
post_data = {"user": "test", "passwd": "testPassword", "next": "/"}
with client as request:
# First, let's test get /login.
response = request.get("/login")
assert response.status_code == int(HTTPStatus.OK)
response = request.post("/login", data=post_data,
allow_redirects=False)
response = request.post("/login", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
# Simulate following the redirect location from above's response.
response = request.get(response.headers.get("location"))
assert response.status_code == int(HTTPStatus.OK)
response = request.post("/logout", data=post_data,
allow_redirects=False)
response = request.post("/logout", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
response = request.post("/logout", data=post_data, cookies={
"AURSID": response.cookies.get("AURSID")
}, allow_redirects=False)
response = request.post(
"/logout",
data=post_data,
cookies={"AURSID": response.cookies.get("AURSID")},
allow_redirects=False,
)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert "AURSID" not in response.cookies
@ -84,11 +83,7 @@ def test_login_suspended(client: TestClient, user: User):
with db.begin():
user.Suspended = 1
data = {
"user": user.Username,
"passwd": "testPassword",
"next": "/"
}
data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
with client as request:
resp = request.post("/login", data=data)
errors = get_errors(resp.text)
@ -96,23 +91,17 @@ def test_login_suspended(client: TestClient, user: User):
def test_login_email(client: TestClient, user: user):
post_data = {
"user": user.Email,
"passwd": "testPassword",
"next": "/"
}
post_data = {"user": user.Email, "passwd": "testPassword", "next": "/"}
with client as request:
resp = request.post("/login", data=post_data,
allow_redirects=False)
resp = request.post("/login", data=post_data, allow_redirects=False)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert "AURSID" in resp.cookies
def mock_getboolean(**overrided_configs):
mocked_config = {
tuple(config.split("__")): value
for config, value in overrided_configs.items()
tuple(config.split("__")): value for config, value in overrided_configs.items()
}
def side_effect(*args):
@ -123,19 +112,14 @@ def mock_getboolean(**overrided_configs):
@mock.patch(
"aurweb.config.getboolean",
side_effect=mock_getboolean(options__disable_http_login=False)
side_effect=mock_getboolean(options__disable_http_login=False),
)
def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User):
post_data = {
"user": user.Username,
"passwd": "testPassword",
"next": "/"
}
post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
# Perform a login request with the data matching our user.
with client as request:
response = request.post("/login", data=post_data,
allow_redirects=False)
response = request.post("/login", data=post_data, allow_redirects=False)
# Make sure we got the expected status out of it.
assert response.status_code == int(HTTPStatus.SEE_OTHER)
@ -152,17 +136,17 @@ def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User):
@mock.patch(
"aurweb.config.getboolean",
side_effect=mock_getboolean(options__disable_http_login=True)
side_effect=mock_getboolean(options__disable_http_login=True),
)
def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User):
""" In this test, we check to verify the course of action taken
"""In this test, we check to verify the course of action taken
by starlette when providing secure=True to a response cookie.
This is achieved by mocking aurweb.config.getboolean to return
True (or 1) when looking for `options.disable_http_login`.
When we receive a response with `disable_http_login` enabled,
we check the fields in cookies received for the secure and
httponly fields, in addition to the rest of the fields given
on such a request. """
on such a request."""
# Create a local TestClient here since we mocked configuration.
# client = TestClient(app)
@ -172,16 +156,11 @@ def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User):
# client.headers.update(TEST_REFERER)
# Data used for our upcoming http post request.
post_data = {
"user": user.Username,
"passwd": "testPassword",
"next": "/"
}
post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
# Perform a login request with the data matching our user.
with client as request:
response = request.post("/login", data=post_data,
allow_redirects=False)
response = request.post("/login", data=post_data, allow_redirects=False)
# Make sure we got the expected status out of it.
assert response.status_code == int(HTTPStatus.SEE_OTHER)
@ -203,16 +182,11 @@ def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User):
def test_authenticated_login(client: TestClient, user: User):
post_data = {
"user": user.Username,
"passwd": "testPassword",
"next": "/"
}
post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
with client as request:
# Try to login.
response = request.post("/login", data=post_data,
allow_redirects=False)
response = request.post("/login", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/"
@ -220,8 +194,9 @@ def test_authenticated_login(client: TestClient, user: User):
# when requesting GET /login as an authenticated user.
# Now, let's verify that we receive 403 Forbidden when we
# try to get /login as an authenticated user.
response = request.get("/login", cookies=response.cookies,
allow_redirects=False)
response = request.get(
"/login", cookies=response.cookies, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.OK)
assert "Logged-in as: <strong>test</strong>" in response.text
@ -236,10 +211,7 @@ def test_unauthenticated_logout_unauthorized(client: TestClient):
def test_login_missing_username(client: TestClient):
post_data = {
"passwd": "testPassword",
"next": "/"
}
post_data = {"passwd": "testPassword", "next": "/"}
with client as request:
response = request.post("/login", data=post_data)
@ -256,17 +228,15 @@ def test_login_remember_me(client: TestClient, user: User):
"user": "test",
"passwd": "testPassword",
"next": "/",
"remember_me": True
"remember_me": True,
}
with client as request:
response = request.post("/login", data=post_data,
allow_redirects=False)
response = request.post("/login", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert "AURSID" in response.cookies
cookie_timeout = aurweb.config.getint(
"options", "persistent_cookie_timeout")
cookie_timeout = aurweb.config.getint("options", "persistent_cookie_timeout")
now_ts = time.utcnow()
session = db.query(Session).filter(Session.UsersID == user.ID).first()
@ -280,7 +250,7 @@ def test_login_incorrect_password_remember_me(client: TestClient, user: User):
"user": "test",
"passwd": "badPassword",
"next": "/",
"remember_me": "on"
"remember_me": "on",
}
with client as request:
@ -295,10 +265,7 @@ def test_login_incorrect_password_remember_me(client: TestClient, user: User):
def test_login_missing_password(client: TestClient):
post_data = {
"user": "test",
"next": "/"
}
post_data = {"user": "test", "next": "/"}
with client as request:
response = request.post("/login", data=post_data)
@ -310,11 +277,7 @@ def test_login_missing_password(client: TestClient):
def test_login_incorrect_password(client: TestClient):
post_data = {
"user": "test",
"passwd": "badPassword",
"next": "/"
}
post_data = {"user": "test", "passwd": "badPassword", "next": "/"}
with client as request:
response = request.post("/login", data=post_data)
@ -350,8 +313,9 @@ def test_login_bad_referer(client: TestClient):
assert "AURSID" not in response.cookies
def test_generate_unique_sid_exhausted(client: TestClient, user: User,
caplog: pytest.LogCaptureFixture):
def test_generate_unique_sid_exhausted(
client: TestClient, user: User, caplog: pytest.LogCaptureFixture
):
"""
In this test, we mock up generate_unique_sid() to infinitely return
the same SessionID given to `user`. Within that mocking, we try
@ -364,13 +328,17 @@ def test_generate_unique_sid_exhausted(client: TestClient, user: User,
now = time.utcnow()
with db.begin():
# Create a second user; we'll login with this one.
user2 = db.create(User, Username="test2", Email="test2@example.org",
ResetKey="testReset", Passwd="testPassword",
AccountTypeID=USER_ID)
user2 = db.create(
User,
Username="test2",
Email="test2@example.org",
ResetKey="testReset",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
# Create a session with ID == "testSession" for `user`.
db.create(Session, User=user, SessionID="testSession",
LastUpdateTS=now)
db.create(Session, User=user, SessionID="testSession", LastUpdateTS=now)
# Mock out generate_unique_sid; always return "testSession" which
# causes us to eventually error out and raise an internal error.

View file

@ -1,9 +1,7 @@
import warnings
from datetime import datetime, timedelta
import pytest
from sqlalchemy import exc as sa_exc
from aurweb import db

View file

@ -11,7 +11,7 @@ def setup(db_test):
class StubRedis:
""" A class which acts as a RedisConnection without using Redis. """
"""A class which acts as a RedisConnection without using Redis."""
cache = dict()
expires = dict()
@ -39,10 +39,13 @@ def redis():
@pytest.mark.asyncio
async def test_db_count_cache(redis):
db.create(User, Username="user1",
Email="user1@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID)
db.create(
User,
Username="user1",
Email="user1@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
query = db.query(User)
@ -57,10 +60,13 @@ async def test_db_count_cache(redis):
@pytest.mark.asyncio
async def test_db_count_cache_expires(redis):
db.create(User, Username="user1",
Email="user1@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID)
db.create(
User,
Username="user1",
Email="user1@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
query = db.query(User)

View file

@ -11,14 +11,14 @@ def setup(db_test):
def test_captcha_salts():
""" Make sure we can get some captcha salts. """
"""Make sure we can get some captcha salts."""
salts = captcha.get_captcha_salts()
assert len(salts) == 6
def test_captcha_token():
""" Make sure getting a captcha salt's token matches up against
the first three digits of the md5 hash of the salt. """
"""Make sure getting a captcha salt's token matches up against
the first three digits of the md5 hash of the salt."""
salts = captcha.get_captcha_salts()
salt = salts[0]
@ -29,9 +29,9 @@ def test_captcha_token():
def test_captcha_challenge_answer():
""" Make sure that executing the captcha challenge via shell
"""Make sure that executing the captcha challenge via shell
produces the correct result by comparing it against a straight
up token conversion. """
up token conversion."""
salts = captcha.get_captcha_salts()
salt = salts[0]
@ -44,7 +44,7 @@ def test_captcha_challenge_answer():
def test_captcha_salt_filter():
""" Make sure captcha_salt_filter returns the first salt from
"""Make sure captcha_salt_filter returns the first salt from
get_captcha_salts().
Example usage:
@ -55,7 +55,7 @@ def test_captcha_salt_filter():
def test_captcha_cmdline_filter():
""" Make sure that the captcha_cmdline filter gives us the
"""Make sure that the captcha_cmdline filter gives us the
same challenge that get_captcha_challenge does.
Example usage:

View file

@ -2,7 +2,6 @@ import configparser
import io
import os
import re
from unittest import mock
import py
@ -35,6 +34,7 @@ def mock_config_get():
if option == "salt_rounds":
return "666"
return config_get(section, option)
return _mock_config_get
@ -59,7 +59,7 @@ def test_config_main_get_unknown_section(get: str):
main()
# With an invalid section, we should get a usage error.
expected = r'^error: no section found$'
expected = r"^error: no section found$"
assert re.match(expected, stderr.getvalue().strip())
@ -140,8 +140,7 @@ def test_config_main_set_immutable():
args = ["aurweb-config", "set", "options", "salt_rounds", "666"]
with mock.patch.dict(os.environ, {"AUR_CONFIG_IMMUTABLE": "1"}):
with mock.patch("sys.argv", args):
with mock.patch("aurweb.config.set_option",
side_effect=mock_set_option):
with mock.patch("aurweb.config.set_option", side_effect=mock_set_option):
main()
expected = None
@ -170,8 +169,7 @@ def test_config_main_set_unknown_section(save: None):
args = ["aurweb-config", "set", "options", "salt_rounds", "666"]
with mock.patch("sys.argv", args):
with mock.patch("sys.stderr", stderr):
with mock.patch("aurweb.config.set_option",
side_effect=mock_set_option):
with mock.patch("aurweb.config.set_option", side_effect=mock_set_option):
main()
assert stderr.getvalue().strip() == "error: no section found"

View file

@ -2,26 +2,26 @@ import os
import re
import sqlite3
import tempfile
from unittest import mock
import pytest
import aurweb.config
import aurweb.initdb
from aurweb import db
from aurweb.models.account_type import AccountType
class Args:
""" Stub arguments used for running aurweb.initdb. """
"""Stub arguments used for running aurweb.initdb."""
use_alembic = True
verbose = True
class DBCursor:
""" A fake database cursor object used in tests. """
"""A fake database cursor object used in tests."""
items = []
def execute(self, *args, **kwargs):
@ -33,7 +33,8 @@ class DBCursor:
class DBConnection:
""" A fake database connection object used in tests. """
"""A fake database connection object used in tests."""
@staticmethod
def cursor():
return DBCursor()
@ -44,7 +45,7 @@ class DBConnection:
def make_temp_config(*replacements):
""" Generate a temporary config file with a set of replacements.
"""Generate a temporary config file with a set of replacements.
:param *replacements: A variable number of tuple regex replacement pairs
:return: A tuple containing (temp directory, temp config file)
@ -85,13 +86,16 @@ def make_temp_config(*replacements):
def make_temp_sqlite_config():
return make_temp_config((r"backend = .*", "backend = sqlite"),
(r"name = .*", "name = /tmp/aurweb.sqlite3"))
return make_temp_config(
(r"backend = .*", "backend = sqlite"),
(r"name = .*", "name = /tmp/aurweb.sqlite3"),
)
def make_temp_mysql_config():
return make_temp_config((r"backend = .*", "backend = mysql"),
(r"name = .*", "name = aurweb_test"))
return make_temp_config(
(r"backend = .*", "backend = mysql"), (r"name = .*", "name = aurweb_test")
)
@pytest.fixture(autouse=True)
@ -150,7 +154,7 @@ def test_sqlalchemy_unknown_backend():
def test_db_connects_without_fail():
""" This only tests the actual config supplied to pytest. """
"""This only tests the actual config supplied to pytest."""
db.connect()

View file

@ -12,8 +12,7 @@ def setup(db_test):
def test_dependency_types():
dep_types = ["depends", "makedepends", "checkdepends", "optdepends"]
for dep_type in dep_types:
dependency_type = query(DependencyType,
DependencyType.Name == dep_type).first()
dependency_type = query(DependencyType, DependencyType.Name == dep_type).first()
assert dependency_type is not None

View file

@ -1,5 +1,4 @@
import io
from subprocess import PIPE, Popen
import pytest
@ -23,7 +22,7 @@ def sendmail(from_: str, to_: str, content: str) -> Email:
def test_email_glue():
""" Test that Email.glue() decodes both base64 and decoded content. """
"""Test that Email.glue() decodes both base64 and decoded content."""
body = "Test email."
sendmail("test@example.org", "test@example.org", body)
assert Email.count() == 1
@ -34,7 +33,7 @@ def test_email_glue():
def test_email_dump():
""" Test that Email.dump() dumps a single email. """
"""Test that Email.dump() dumps a single email."""
body = "Test email."
sendmail("test@example.org", "test@example.org", body)
assert Email.count() == 1
@ -46,7 +45,7 @@ def test_email_dump():
def test_email_dump_multiple():
""" Test that Email.dump() dumps multiple emails. """
"""Test that Email.dump() dumps multiple emails."""
body = "Test email."
sendmail("test@example.org", "test@example.org", body)
sendmail("test2@example.org", "test2@example.org", body)

View file

@ -1,5 +1,4 @@
import py
from _pytest.logging import LogCaptureFixture
from aurweb.testing.filelock import FileLock

View file

@ -22,7 +22,7 @@ def test_number_format():
def test_extend_query():
""" Test extension of a query via extend_query. """
"""Test extension of a query via extend_query."""
query = {"a": "b"}
extended = filters.extend_query(query, ("a", "c"), ("b", "d"))
assert extended.get("a") == "c"
@ -30,7 +30,7 @@ def test_extend_query():
def test_to_qs():
""" Test conversion from a query dictionary to a query string. """
"""Test conversion from a query dictionary to a query string."""
query = {"a": "b", "c": [1, 2, 3]}
qs = filters.to_qs(query)
assert qs == "a=b&c=1&c=2&c=3"

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db

View file

@ -1,10 +1,8 @@
import re
from http import HTTPStatus
from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
from aurweb import db, time
@ -31,16 +29,26 @@ def setup(db_test):
@pytest.fixture
def user():
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
Passwd="testPassword", AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def user2():
with db.begin():
user = db.create(User, Username="test2", Email="test2@example.org",
Passwd="testPassword", AccountTypeID=USER_ID)
user = db.create(
User,
Username="test2",
Email="test2@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -50,10 +58,17 @@ def redis():
def delete_keys():
# Cleanup keys if they exist.
for key in ("package_count", "orphan_count", "user_count",
"trusted_user_count", "seven_days_old_added",
"seven_days_old_updated", "year_old_updated",
"never_updated", "package_updates"):
for key in (
"package_count",
"orphan_count",
"user_count",
"trusted_user_count",
"seven_days_old_added",
"seven_days_old_updated",
"year_old_updated",
"never_updated",
"package_updates",
):
if redis.get(key) is not None:
redis.delete(key)
@ -66,16 +81,21 @@ def redis():
def package(user: User) -> Package:
now = time.utcnow()
with db.begin():
pkgbase = db.create(PackageBase, Name="test-pkg",
Maintainer=user, Packager=user,
SubmittedTS=now, ModifiedTS=now)
pkgbase = db.create(
PackageBase,
Name="test-pkg",
Maintainer=user,
Packager=user,
SubmittedTS=now,
ModifiedTS=now,
)
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
yield pkg
@pytest.fixture
def packages(user):
""" Yield a list of num_packages Package objects maintained by user. """
"""Yield a list of num_packages Package objects maintained by user."""
num_packages = 50 # Tunable
# For i..num_packages, create a package named pkg_{i}.
@ -83,9 +103,14 @@ def packages(user):
now = time.utcnow()
with db.begin():
for i in range(num_packages):
pkgbase = db.create(PackageBase, Name=f"pkg_{i}",
Maintainer=user, Packager=user,
SubmittedTS=now, ModifiedTS=now)
pkgbase = db.create(
PackageBase,
Name=f"pkg_{i}",
Maintainer=user,
Packager=user,
SubmittedTS=now,
ModifiedTS=now,
)
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
pkgs.append(pkg)
now += 1
@ -99,9 +124,9 @@ def test_homepage():
assert response.status_code == int(HTTPStatus.OK)
@patch('aurweb.util.get_ssh_fingerprints')
@patch("aurweb.util.get_ssh_fingerprints")
def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock):
fingerprints = {'Ed25519': "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"}
fingerprints = {"Ed25519": "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"}
get_ssh_fingerprints_mock.return_value = fingerprints
with client as request:
@ -110,17 +135,23 @@ def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock):
for key, value in fingerprints.items():
assert key in response.content.decode()
assert value in response.content.decode()
assert 'The following SSH fingerprints are used for the AUR' in response.content.decode()
assert (
"The following SSH fingerprints are used for the AUR"
in response.content.decode()
)
@patch('aurweb.util.get_ssh_fingerprints')
@patch("aurweb.util.get_ssh_fingerprints")
def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock):
get_ssh_fingerprints_mock.return_value = {}
with client as request:
response = request.get("/")
assert 'The following SSH fingerprints are used for the AUR' not in response.content.decode()
assert (
"The following SSH fingerprints are used for the AUR"
not in response.content.decode()
)
def test_homepage_stats(redis, packages):
@ -131,20 +162,20 @@ def test_homepage_stats(redis, packages):
root = parse_root(response.text)
expectations = [
("Packages", r'\d+'),
("Orphan Packages", r'\d+'),
("Packages added in the past 7 days", r'\d+'),
("Packages updated in the past 7 days", r'\d+'),
("Packages updated in the past year", r'\d+'),
("Packages never updated", r'\d+'),
("Registered Users", r'\d+'),
("Trusted Users", r'\d+')
("Packages", r"\d+"),
("Orphan Packages", r"\d+"),
("Packages added in the past 7 days", r"\d+"),
("Packages updated in the past 7 days", r"\d+"),
("Packages updated in the past year", r"\d+"),
("Packages never updated", r"\d+"),
("Registered Users", r"\d+"),
("Trusted Users", r"\d+"),
]
stats = root.xpath('//div[@id="pkg-stats"]//tr')
for i, expected in enumerate(expectations):
expected_key, expected_regex = expected
key, value = stats[i].xpath('./td')
key, value = stats[i].xpath("./td")
assert key.text.strip() == expected_key
assert re.match(expected_regex, value.text.strip())
@ -165,7 +196,7 @@ def test_homepage_updates(redis, packages):
expectations = [f"pkg_{i}" for i in range(50 - 1, 50 - 1 - 15, -1)]
updates = root.xpath('//div[@id="pkg-updates"]/table/tbody/tr')
for i, expected in enumerate(expectations):
pkgname = updates[i].xpath('./td/a').pop(0)
pkgname = updates[i].xpath("./td/a").pop(0)
assert pkgname.text.strip() == expected
@ -173,9 +204,9 @@ def test_homepage_dashboard(redis, packages, user):
# Create Comaintainer records for all of the packages.
with db.begin():
for pkg in packages:
db.create(PackageComaintainer,
PackageBase=pkg.PackageBase,
User=user, Priority=1)
db.create(
PackageComaintainer, PackageBase=pkg.PackageBase, User=user, Priority=1
)
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
@ -189,16 +220,18 @@ def test_homepage_dashboard(redis, packages, user):
expectations = [f"pkg_{i}" for i in range(50 - 1, 0, -1)]
my_packages = root.xpath('//table[@id="my-packages"]/tbody/tr')
for i, expected in enumerate(expectations):
name, version, votes, pop, voted, notify, desc, maint \
= my_packages[i].xpath('./td')
assert name.xpath('./a').pop(0).text.strip() == expected
name, version, votes, pop, voted, notify, desc, maint = my_packages[i].xpath(
"./td"
)
assert name.xpath("./a").pop(0).text.strip() == expected
# Do the same for the Comaintained Packages table.
my_packages = root.xpath('//table[@id="comaintained-packages"]/tbody/tr')
for i, expected in enumerate(expectations):
name, version, votes, pop, voted, notify, desc, maint \
= my_packages[i].xpath('./td')
assert name.xpath('./a').pop(0).text.strip() == expected
name, version, votes, pop, voted, notify, desc, maint = my_packages[i].xpath(
"./td"
)
assert name.xpath("./a").pop(0).text.strip() == expected
def test_homepage_dashboard_requests(redis, packages, user):
@ -207,11 +240,16 @@ def test_homepage_dashboard_requests(redis, packages, user):
pkg = packages[0]
reqtype = db.query(RequestType, RequestType.ID == DELETION_ID).first()
with db.begin():
pkgreq = db.create(PackageRequest, PackageBase=pkg.PackageBase,
PackageBaseName=pkg.PackageBase.Name,
User=user, Comments=str(),
ClosureComment=str(), RequestTS=now,
RequestType=reqtype)
pkgreq = db.create(
PackageRequest,
PackageBase=pkg.PackageBase,
PackageBaseName=pkg.PackageBase.Name,
User=user,
Comments=str(),
ClosureComment=str(),
RequestTS=now,
RequestType=reqtype,
)
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
@ -220,7 +258,7 @@ def test_homepage_dashboard_requests(redis, packages, user):
root = parse_root(response.text)
request = root.xpath('//table[@id="pkgreq-results"]/tbody/tr').pop(0)
pkgname = request.xpath('./td/a').pop(0)
pkgname = request.xpath("./td/a").pop(0)
assert pkgname.text.strip() == pkgreq.PackageBaseName
@ -238,7 +276,7 @@ def test_homepage_dashboard_flagged_packages(redis, packages, user):
# Check to see that the package showed up in the Flagged Packages table.
root = parse_root(response.text)
flagged_pkg = root.xpath('//table[@id="flagged-packages"]/tbody/tr').pop(0)
flagged_name = flagged_pkg.xpath('./td/a').pop(0)
flagged_name = flagged_pkg.xpath("./td/a").pop(0)
assert flagged_name.text.strip() == pkg.Name
@ -247,8 +285,7 @@ def test_homepage_dashboard_flagged(user: User, user2: User, package: Package):
now = time.utcnow()
with db.begin():
db.create(PackageComaintainer, User=user2,
PackageBase=pkgbase, Priority=1)
db.create(PackageComaintainer, User=user2, PackageBase=pkgbase, Priority=1)
pkgbase.OutOfDateTS = now - 5
pkgbase.Flagger = user

View file

@ -2,13 +2,11 @@
import hashlib
import os
import tempfile
from http import HTTPStatus
from unittest import mock
import fastapi
import pytest
from fastapi import HTTPException
from fastapi.testclient import TestClient
@ -33,8 +31,13 @@ def client() -> TestClient:
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
Passwd="testPassword", AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -53,12 +56,7 @@ def pkgbase(user: User) -> PackageBase:
def test_archdev_navbar(client: TestClient):
expected = [
"AUR Home",
"Packages",
"Register",
"Login"
]
expected = ["AUR Home", "Packages", "Register", "Login"]
with client as request:
resp = request.get("/")
assert resp.status_code == int(HTTPStatus.OK)
@ -70,13 +68,7 @@ def test_archdev_navbar(client: TestClient):
def test_archdev_navbar_authenticated(client: TestClient, user: User):
expected = [
"Dashboard",
"Packages",
"Requests",
"My Account",
"Logout"
]
expected = ["Dashboard", "Packages", "Requests", "My Account", "Logout"]
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.get("/", cookies=cookies)
@ -88,8 +80,7 @@ def test_archdev_navbar_authenticated(client: TestClient, user: User):
assert item.text.strip() == expected[i]
def test_archdev_navbar_authenticated_tu(client: TestClient,
trusted_user: User):
def test_archdev_navbar_authenticated_tu(client: TestClient, trusted_user: User):
expected = [
"Dashboard",
"Packages",
@ -97,7 +88,7 @@ def test_archdev_navbar_authenticated_tu(client: TestClient,
"Accounts",
"My Account",
"Trusted User",
"Logout"
"Logout",
]
cookies = {"AURSID": trusted_user.login(Request(), "testPassword")}
with client as request:
@ -131,7 +122,7 @@ def test_get_successes():
def test_archive_sig(client: TestClient):
hash_value = hashlib.sha256(b'test').hexdigest()
hash_value = hashlib.sha256(b"test").hexdigest()
with tempfile.TemporaryDirectory() as tmpdir:
packages_sha256 = os.path.join(tmpdir, "packages.gz.sha256")
@ -179,12 +170,7 @@ def test_disabled_metrics(client: TestClient):
def test_rtl(client: TestClient):
responses = {}
expected = [
[],
[],
['rtl'],
['rtl']
]
expected = [[], [], ["rtl"], ["rtl"]]
with client as request:
responses["default"] = request.get("/")
responses["de"] = request.get("/", cookies={"AURLANG": "de"})
@ -193,11 +179,11 @@ def test_rtl(client: TestClient):
for i, (lang, resp) in enumerate(responses.items()):
assert resp.status_code == int(HTTPStatus.OK)
t = parse_root(resp.text)
assert t.xpath('//html/@dir') == expected[i]
assert t.xpath("//html/@dir") == expected[i]
def test_404_with_valid_pkgbase(client: TestClient, pkgbase: PackageBase):
""" Test HTTPException with status_code == 404 and valid pkgbase. """
"""Test HTTPException with status_code == 404 and valid pkgbase."""
endpoint = f"/{pkgbase.Name}"
with client as request:
response = request.get(endpoint)
@ -209,7 +195,7 @@ def test_404_with_valid_pkgbase(client: TestClient, pkgbase: PackageBase):
def test_404(client: TestClient):
""" Test HTTPException with status_code == 404 without a valid pkgbase. """
"""Test HTTPException with status_code == 404 without a valid pkgbase."""
with client as request:
response = request.get("/nonexistentroute")
assert response.status_code == int(HTTPStatus.NOT_FOUND)
@ -221,7 +207,8 @@ def test_404(client: TestClient):
def test_503(client: TestClient):
""" Test HTTPException with status_code == 503 (Service Unavailable). """
"""Test HTTPException with status_code == 503 (Service Unavailable)."""
@asgi.app.get("/raise-503")
async def raise_503(request: fastapi.Request):
raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE)

View file

@ -3,7 +3,6 @@ import pytest
import aurweb.config
import aurweb.db
import aurweb.initdb
from aurweb.models.account_type import AccountType
@ -19,11 +18,11 @@ class Args:
def test_run():
from aurweb.schema import metadata
aurweb.db.kill_engine()
metadata.drop_all(aurweb.db.get_engine())
aurweb.initdb.run(Args())
# Check that constant table rows got added via initdb.
record = aurweb.db.query(AccountType,
AccountType.AccountType == "User").first()
record = aurweb.db.query(AccountType, AccountType.AccountType == "User").first()
assert record is not None

View file

@ -4,13 +4,13 @@ from aurweb.testing.requests import Request
def test_translator():
""" Test creating l10n translation tools. """
"""Test creating l10n translation tools."""
de_home = l10n.translator.translate("Home", "de")
assert de_home == "Startseite"
def test_get_request_language():
""" First, tests default_lang, then tests a modified AURLANG cookie. """
"""First, tests default_lang, then tests a modified AURLANG cookie."""
request = Request()
assert l10n.get_request_language(request) == "en"
@ -19,18 +19,17 @@ def test_get_request_language():
def test_get_raw_translator_for_request():
""" Make sure that get_raw_translator_for_request is giving us
the translator we expect. """
"""Make sure that get_raw_translator_for_request is giving us
the translator we expect."""
request = Request()
request.cookies["AURLANG"] = "de"
translator = l10n.get_raw_translator_for_request(request)
assert translator.gettext("Home") == \
l10n.translator.translate("Home", "de")
assert translator.gettext("Home") == l10n.translator.translate("Home", "de")
def test_get_translator_for_request():
""" Make sure that get_translator_for_request is giving us back
our expected translation function. """
"""Make sure that get_translator_for_request is giving us back
our expected translation function."""
request = Request()
request.cookies["AURLANG"] = "de"
@ -43,10 +42,8 @@ def test_tn_filter():
request.cookies["AURLANG"] = "en"
context = {"language": "en", "request": request}
translated = filters.tn(context, 1, "%d package found.",
"%d packages found.")
translated = filters.tn(context, 1, "%d package found.", "%d packages found.")
assert translated == "%d package found."
translated = filters.tn(context, 2, "%d package found.",
"%d packages found.")
translated = filters.tn(context, 2, "%d package found.", "%d packages found.")
assert translated == "%d packages found."

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db

View file

@ -1,14 +1,20 @@
import gzip
import json
import os
from unittest import mock
import py
import pytest
from aurweb import config, db
from aurweb.models import License, Package, PackageBase, PackageDependency, PackageLicense, User
from aurweb.models import (
License,
Package,
PackageBase,
PackageDependency,
PackageLicense,
User,
)
from aurweb.models.account_type import USER_ID
from aurweb.models.dependency_type import DEPENDS_ID
@ -38,10 +44,13 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test",
Email="test@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -52,16 +61,18 @@ def packages(user: User) -> list[Package]:
lic = db.create(License, Name="GPL")
for i in range(5):
# Create the package.
pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}",
Packager=user)
pkg = db.create(Package, PackageBase=pkgbase,
Name=f"pkg_{i}")
pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}", Packager=user)
pkg = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}")
# Create some related records.
db.create(PackageLicense, Package=pkg, License=lic)
db.create(PackageDependency, DepTypeID=DEPENDS_ID,
Package=pkg, DepName=f"dep_{i}",
DepCondition=">=1.0")
db.create(
PackageDependency,
DepTypeID=DEPENDS_ID,
Package=pkg,
DepName=f"dep_{i}",
DepCondition=">=1.0",
)
# Add the package to our output list.
output.append(pkg)
@ -88,8 +99,11 @@ def config_mock(tmpdir: py.path.local) -> None:
config.rehash()
def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packages: list[Package]):
def test_mkpkglists(
tmpdir: py.path.local, config_mock: None, user: User, packages: list[Package]
):
from aurweb.scripts import mkpkglists
mkpkglists.main()
PACKAGES = config.get("mkpkglists", "packagesfile")
@ -106,10 +120,7 @@ def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packag
PKGBASE,
"pkgbase_0\npkgbase_1\npkgbase_2\npkgbase_3\npkgbase_4\n",
),
(
USERS,
"test\n"
),
(USERS, "test\n"),
]
for (file, expected_content) in expectations:
@ -136,6 +147,7 @@ def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packag
@mock.patch("sys.argv", ["mkpkglists", "--extended"])
def test_mkpkglists_extended_empty(config_mock: None):
from aurweb.scripts import mkpkglists
mkpkglists.main()
PACKAGES = config.get("mkpkglists", "packagesfile")
@ -166,9 +178,9 @@ def test_mkpkglists_extended_empty(config_mock: None):
@mock.patch("sys.argv", ["mkpkglists", "--extended"])
def test_mkpkglists_extended(config_mock: None, user: User,
packages: list[Package]):
def test_mkpkglists_extended(config_mock: None, user: User, packages: list[Package]):
from aurweb.scripts import mkpkglists
mkpkglists.main()
PACKAGES = config.get("mkpkglists", "packagesfile")
@ -186,10 +198,7 @@ def test_mkpkglists_extended(config_mock: None, user: User,
PKGBASE,
"pkgbase_0\npkgbase_1\npkgbase_2\npkgbase_3\npkgbase_4\n",
),
(
USERS,
"test\n"
),
(USERS, "test\n"),
]
for (file, expected_content) in expectations:

View file

@ -23,24 +23,39 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
Passwd=str(), AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def user1() -> User:
with db.begin():
user1 = db.create(User, Username="user1", Email="user1@example.org",
Passwd=str(), AccountTypeID=USER_ID)
user1 = db.create(
User,
Username="user1",
Email="user1@example.org",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user1
@pytest.fixture
def user2() -> User:
with db.begin():
user2 = db.create(User, Username="user2", Email="user2@example.org",
Passwd=str(), AccountTypeID=USER_ID)
user2 = db.create(
User,
Username="user2",
Email="user2@example.org",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user2
@ -52,11 +67,15 @@ def pkgbases(user: User) -> list[PackageBase]:
with db.begin():
for i in range(5):
output.append(
db.create(PackageBase, Name=f"pkgbase_{i}",
Maintainer=user, SubmittedTS=now,
ModifiedTS=now))
db.create(models.PackageNotification, PackageBase=output[-1],
User=user)
db.create(
PackageBase,
Name=f"pkgbase_{i}",
Maintainer=user,
SubmittedTS=now,
ModifiedTS=now,
)
)
db.create(models.PackageNotification, PackageBase=output[-1], User=user)
yield output
@ -64,11 +83,15 @@ def pkgbases(user: User) -> list[PackageBase]:
def pkgreq(user2: User, pkgbases: list[PackageBase]):
pkgbase = pkgbases[0]
with db.begin():
pkgreq_ = db.create(PackageRequest, PackageBase=pkgbase,
PackageBaseName=pkgbase.Name, User=user2,
ReqTypeID=ORPHAN_ID,
Comments="This is a request test comment.",
ClosureComment=str())
pkgreq_ = db.create(
PackageRequest,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
User=user2,
ReqTypeID=ORPHAN_ID,
Comments="This is a request test comment.",
ClosureComment=str(),
)
yield pkgreq_
@ -78,21 +101,24 @@ def packages(pkgbases: list[PackageBase]) -> list[Package]:
with db.begin():
for i, pkgbase in enumerate(pkgbases):
output.append(
db.create(Package, PackageBase=pkgbase,
Name=f"pkg_{i}", Version=f"{i}.0"))
db.create(
Package, PackageBase=pkgbase, Name=f"pkg_{i}", Version=f"{i}.0"
)
)
yield output
def test_out_of_date(user: User, user1: User, user2: User,
pkgbases: list[PackageBase]):
def test_out_of_date(user: User, user1: User, user2: User, pkgbases: list[PackageBase]):
pkgbase = pkgbases[0]
# Create two comaintainers. We'll pass the maintainer uid to
# FlagNotification, so we should expect to get two emails.
with db.begin():
db.create(models.PackageComaintainer,
PackageBase=pkgbase, User=user1, Priority=1)
db.create(models.PackageComaintainer,
PackageBase=pkgbase, User=user2, Priority=2)
db.create(
models.PackageComaintainer, PackageBase=pkgbase, User=user1, Priority=1
)
db.create(
models.PackageComaintainer, PackageBase=pkgbase, User=user2, Priority=2
)
# Send the notification for pkgbases[0].
notif = notify.FlagNotification(user.ID, pkgbases[0].ID)
@ -165,8 +191,12 @@ def test_comment(user: User, user2: User, pkgbases: list[PackageBase]):
pkgbase = pkgbases[0]
with db.begin():
comment = db.create(models.PackageComment, PackageBase=pkgbase,
User=user2, Comments="This is a test comment.")
comment = db.create(
models.PackageComment,
PackageBase=pkgbase,
User=user2,
Comments="This is a test comment.",
)
rendercomment.update_comment_render_fastapi(comment)
notif = notify.CommentNotification(user2.ID, pkgbase.ID, comment.ID)
@ -366,15 +396,16 @@ def set_tu(users: list[User]) -> User:
user.AccountTypeID = TRUSTED_USER_ID
def test_open_close_request(user: User, user2: User,
pkgreq: PackageRequest,
pkgbases: list[PackageBase]):
def test_open_close_request(
user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase]
):
set_tu([user])
pkgbase = pkgbases[0]
# Send an open request notification.
notif = notify.RequestOpenNotification(
user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID)
user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID
)
notif.send()
assert Email.count() == 1
@ -420,22 +451,24 @@ Request #{pkgreq.ID} has been rejected by {user2.Username} [1].
email = Email(3).parse()
assert email.headers.get("To") == aur_request_ml
assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email])
expected = (f"[PRQ#{pkgreq.ID}] Orphan Request for "
f"{pkgbase.Name} Accepted")
expected = f"[PRQ#{pkgreq.ID}] Orphan Request for " f"{pkgbase.Name} Accepted"
assert email.headers.get("Subject") == expected
expected = (f"Request #{pkgreq.ID} has been accepted automatically "
"by the Arch User Repository\npackage request system.")
expected = (
f"Request #{pkgreq.ID} has been accepted automatically "
"by the Arch User Repository\npackage request system."
)
assert email.body == expected
def test_close_request_comaintainer_cc(user: User, user2: User,
pkgreq: PackageRequest,
pkgbases: list[PackageBase]):
def test_close_request_comaintainer_cc(
user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase]
):
pkgbase = pkgbases[0]
with db.begin():
db.create(models.PackageComaintainer, PackageBase=pkgbase,
User=user2, Priority=1)
db.create(
models.PackageComaintainer, PackageBase=pkgbase, User=user2, Priority=1
)
notif = notify.RequestCloseNotification(0, pkgreq.ID, "accepted")
notif.send()
@ -446,9 +479,9 @@ def test_close_request_comaintainer_cc(user: User, user2: User,
assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email])
def test_close_request_closure_comment(user: User, user2: User,
pkgreq: PackageRequest,
pkgbases: list[PackageBase]):
def test_close_request_closure_comment(
user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase]
):
pkgbase = pkgbases[0]
with db.begin():
pkgreq.ClosureComment = "This is a test closure comment."
@ -496,7 +529,7 @@ ends in less than 48 hours.
def test_notify_main(user: User):
""" Test TU vote reminder through aurweb.notify.main(). """
"""Test TU vote reminder through aurweb.notify.main()."""
set_tu([user])
vote_id = 1
@ -539,6 +572,7 @@ def mock_smtp_config(cls):
elif key == "smtp-password":
return cls()
return cls(config_get(section, key))
return _mock_smtp_config
@ -574,6 +608,7 @@ def mock_smtp_starttls_config(cls):
elif key == "smtp-password":
return cls("password")
return cls(config_get(section, key))
return _mock_smtp_starttls_config
@ -590,8 +625,7 @@ def test_smtp_starttls(user: User):
get = "aurweb.config.get"
getboolean = "aurweb.config.getboolean"
with mock.patch(get, side_effect=mock_smtp_starttls_config(str)):
with mock.patch(
getboolean, side_effect=mock_smtp_starttls_config(bool)):
with mock.patch(getboolean, side_effect=mock_smtp_starttls_config(bool)):
with mock.patch("smtplib.SMTP", side_effect=smtp):
notif = notify.WelcomeNotification(user.ID)
notif.send()
@ -621,6 +655,7 @@ def mock_smtp_ssl_config(cls):
elif key == "smtp-password":
return cls("password")
return cls(config_get(section, key))
return _mock_smtp_ssl_config
@ -651,7 +686,7 @@ def test_notification_defaults():
def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture):
""" Try sending a notification with a bad SMTP configuration. """
"""Try sending a notification with a bad SMTP configuration."""
caplog.set_level(ERROR)
config_get = config.get
config_getint = config.getint

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -13,10 +12,12 @@ def setup(db_test):
def test_official_provider_creation():
with db.begin():
oprovider = db.create(OfficialProvider,
Name="some-name",
Repo="some-repo",
Provides="some-provides")
oprovider = db.create(
OfficialProvider,
Name="some-name",
Repo="some-repo",
Provides="some-provides",
)
assert bool(oprovider.ID)
assert oprovider.Name == "some-name"
assert oprovider.Repo == "some-repo"
@ -24,19 +25,23 @@ def test_official_provider_creation():
def test_official_provider_cs():
""" Test case sensitivity of the database table. """
"""Test case sensitivity of the database table."""
with db.begin():
oprovider = db.create(OfficialProvider,
Name="some-name",
Repo="some-repo",
Provides="some-provides")
oprovider = db.create(
OfficialProvider,
Name="some-name",
Repo="some-repo",
Provides="some-provides",
)
assert bool(oprovider.ID)
with db.begin():
oprovider_cs = db.create(OfficialProvider,
Name="SOME-NAME",
Repo="SOME-REPO",
Provides="SOME-PROVIDES")
oprovider_cs = db.create(
OfficialProvider,
Name="SOME-NAME",
Repo="SOME-REPO",
Provides="SOME-PROVIDES",
)
assert bool(oprovider_cs.ID)
assert oprovider.ID != oprovider_cs.ID

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy import and_
from sqlalchemy.exc import IntegrityError
@ -20,20 +19,28 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def package(user: User) -> Package:
with db.begin():
pkgbase = db.create(PackageBase, Name="beautiful-package",
Maintainer=user)
package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
Description="Test description.",
URL="https://test.package")
pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user)
package = db.create(
Package,
PackageBase=pkgbase,
Name=pkgbase.Name,
Description="Test description.",
URL="https://test.package",
)
yield package
@ -48,21 +55,28 @@ def test_package(package: Package):
package.Version = "1.2.3"
# Make sure it got updated in the database.
record = db.query(Package).filter(
and_(Package.ID == package.ID,
Package.Version == "1.2.3")
).first()
record = (
db.query(Package)
.filter(and_(Package.ID == package.ID, Package.Version == "1.2.3"))
.first()
)
assert record is not None
def test_package_null_pkgbase_raises():
with pytest.raises(IntegrityError):
Package(Name="some-package", Description="Some description.",
URL="https://some.package")
Package(
Name="some-package",
Description="Some description.",
URL="https://some.package",
)
def test_package_null_name_raises(package: Package):
pkgbase = package.PackageBase
with pytest.raises(IntegrityError):
Package(PackageBase=pkgbase, Description="Some description.",
URL="https://some.package")
Package(
PackageBase=pkgbase,
Description="Some description.",
URL="https://some.package",
)

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -16,17 +15,21 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def pkgbase(user: User) -> PackageBase:
with db.begin():
pkgbase = db.create(PackageBase, Name="beautiful-package",
Maintainer=user)
pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user)
yield pkgbase
@ -44,7 +47,7 @@ def test_package_base(user: User, pkgbase: PackageBase):
def test_package_base_ci(user: User, pkgbase: PackageBase):
""" Test case insensitivity of the database table. """
"""Test case insensitivity of the database table."""
with pytest.raises(IntegrityError):
with db.begin():
db.create(PackageBase, Name=pkgbase.Name.upper(), Maintainer=user)

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -32,8 +36,9 @@ def pkgbase(user: User) -> PackageBase:
def test_package_comaintainer_creation(user: User, pkgbase: PackageBase):
with db.begin():
package_comaintainer = db.create(PackageComaintainer, User=user,
PackageBase=pkgbase, Priority=5)
package_comaintainer = db.create(
PackageComaintainer, User=user, PackageBase=pkgbase, Priority=5
)
assert bool(package_comaintainer)
assert package_comaintainer.User == user
assert package_comaintainer.PackageBase == pkgbase
@ -50,7 +55,6 @@ def test_package_comaintainer_null_pkgbase_raises(user: User):
PackageComaintainer(User=user, Priority=1)
def test_package_comaintainer_null_priority_raises(user: User,
pkgbase: PackageBase):
def test_package_comaintainer_null_priority_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageComaintainer(User=user, PackageBase=pkgbase)

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -32,35 +36,46 @@ def pkgbase(user: User) -> PackageBase:
def test_package_comment_creation(user: User, pkgbase: PackageBase):
with db.begin():
package_comment = db.create(PackageComment, PackageBase=pkgbase,
User=user, Comments="Test comment.",
RenderedComment="Test rendered comment.")
package_comment = db.create(
PackageComment,
PackageBase=pkgbase,
User=user,
Comments="Test comment.",
RenderedComment="Test rendered comment.",
)
assert bool(package_comment.ID)
def test_package_comment_null_pkgbase_raises(user: User):
with pytest.raises(IntegrityError):
PackageComment(User=user, Comments="Test comment.",
RenderedComment="Test rendered comment.")
PackageComment(
User=user,
Comments="Test comment.",
RenderedComment="Test rendered comment.",
)
def test_package_comment_null_user_raises(pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageComment(PackageBase=pkgbase,
Comments="Test comment.",
RenderedComment="Test rendered comment.")
PackageComment(
PackageBase=pkgbase,
Comments="Test comment.",
RenderedComment="Test rendered comment.",
)
def test_package_comment_null_comments_raises(user: User,
pkgbase: PackageBase):
def test_package_comment_null_comments_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageComment(PackageBase=pkgbase, User=user,
RenderedComment="Test rendered comment.")
PackageComment(
PackageBase=pkgbase, User=user, RenderedComment="Test rendered comment."
)
def test_package_comment_null_renderedcomment_defaults(user: User,
pkgbase: PackageBase):
def test_package_comment_null_renderedcomment_defaults(
user: User, pkgbase: PackageBase
):
with db.begin():
record = db.create(PackageComment, PackageBase=pkgbase,
User=user, Comments="Test comment.")
record = db.create(
PackageComment, PackageBase=pkgbase, User=user, Comments="Test comment."
)
assert record.RenderedComment == str()

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd=str(),
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user
@ -29,16 +33,21 @@ def user() -> User:
def package(user: User) -> Package:
with db.begin():
pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user)
package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
Description="Test description.",
URL="https://test.package")
package = db.create(
Package,
PackageBase=pkgbase,
Name=pkgbase.Name,
Description="Test description.",
URL="https://test.package",
)
yield package
def test_package_dependencies(user: User, package: Package):
with db.begin():
pkgdep = db.create(PackageDependency, Package=package,
DepTypeID=DEPENDS_ID, DepName="test-dep")
pkgdep = db.create(
PackageDependency, Package=package, DepTypeID=DEPENDS_ID, DepName="test-dep"
)
assert pkgdep.DepName == "test-dep"
assert pkgdep.Package == package
assert pkgdep in package.package_dependencies

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -17,24 +16,27 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def pkgbase(user: User) -> PackageBase:
with db.begin():
pkgbase = db.create(PackageBase, Name="beautiful-package",
Maintainer=user)
pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user)
yield pkgbase
def test_package_keyword(pkgbase: PackageBase):
with db.begin():
pkg_keyword = db.create(PackageKeyword, PackageBase=pkgbase,
Keyword="test")
pkg_keyword = db.create(PackageKeyword, PackageBase=pkgbase, Keyword="test")
assert pkg_keyword in pkgbase.keywords
assert pkgbase == pkg_keyword.PackageBase

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -42,8 +46,7 @@ def package(user: User, license: License):
def test_package_license(license: License, package: Package):
with db.begin():
package_license = db.create(PackageLicense, Package=package,
License=license)
package_license = db.create(PackageLicense, Package=package, License=license)
assert package_license.License == license
assert package_license.Package == package

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -16,8 +15,13 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword")
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
)
yield user
@ -31,7 +35,8 @@ def pkgbase(user: User) -> PackageBase:
def test_package_notification_creation(user: User, pkgbase: PackageBase):
with db.begin():
package_notification = db.create(
PackageNotification, User=user, PackageBase=pkgbase)
PackageNotification, User=user, PackageBase=pkgbase
)
assert bool(package_notification)
assert package_notification.User == user
assert package_notification.PackageBase == pkgbase

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -29,17 +33,24 @@ def user() -> User:
def package(user: User) -> Package:
with db.begin():
pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user)
package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
Description="Test description.",
URL="https://test.package")
package = db.create(
Package,
PackageBase=pkgbase,
Name=pkgbase.Name,
Description="Test description.",
URL="https://test.package",
)
yield package
def test_package_relation(package: Package):
with db.begin():
pkgrel = db.create(PackageRelation, Package=package,
RelTypeID=CONFLICTS_ID,
RelName="test-relation")
pkgrel = db.create(
PackageRelation,
Package=package,
RelTypeID=CONFLICTS_ID,
RelName="test-relation",
)
assert pkgrel.RelName == "test-relation"
assert pkgrel.Package == package

View file

@ -1,12 +1,20 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
from aurweb.models.account_type import USER_ID
from aurweb.models.package_base import PackageBase
from aurweb.models.package_request import (ACCEPTED, ACCEPTED_ID, CLOSED, CLOSED_ID, PENDING, PENDING_ID, REJECTED,
REJECTED_ID, PackageRequest)
from aurweb.models.package_request import (
ACCEPTED,
ACCEPTED_ID,
CLOSED,
CLOSED_ID,
PENDING,
PENDING_ID,
REJECTED,
REJECTED_ID,
PackageRequest,
)
from aurweb.models.request_type import MERGE_ID
from aurweb.models.user import User
@ -19,9 +27,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -34,10 +47,15 @@ def pkgbase(user: User) -> PackageBase:
def test_package_request_creation(user: User, pkgbase: PackageBase):
with db.begin():
package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID,
User=user, PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(), ClosureComment=str())
package_request = db.create(
PackageRequest,
ReqTypeID=MERGE_ID,
User=user,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(),
ClosureComment=str(),
)
assert bool(package_request.ID)
assert package_request.User == user
@ -54,11 +72,17 @@ def test_package_request_creation(user: User, pkgbase: PackageBase):
def test_package_request_closed(user: User, pkgbase: PackageBase):
ts = time.utcnow()
with db.begin():
package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID,
User=user, PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Closer=user, ClosedTS=ts,
Comments=str(), ClosureComment=str())
package_request = db.create(
PackageRequest,
ReqTypeID=MERGE_ID,
User=user,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Closer=user,
ClosedTS=ts,
Comments=str(),
ClosureComment=str(),
)
assert package_request.Closer == user
assert package_request.ClosedTS == ts
@ -67,61 +91,87 @@ def test_package_request_closed(user: User, pkgbase: PackageBase):
assert package_request in user.closed_requests
def test_package_request_null_request_type_raises(user: User,
pkgbase: PackageBase):
def test_package_request_null_request_type_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageRequest(User=user, PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(), ClosureComment=str())
PackageRequest(
User=user,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(),
ClosureComment=str(),
)
def test_package_request_null_user_raises(pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageRequest(ReqTypeID=MERGE_ID,
PackageBase=pkgbase, PackageBaseName=pkgbase.Name,
Comments=str(), ClosureComment=str())
PackageRequest(
ReqTypeID=MERGE_ID,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(),
ClosureComment=str(),
)
def test_package_request_null_package_base_raises(user: User,
pkgbase: PackageBase):
def test_package_request_null_package_base_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageRequest(ReqTypeID=MERGE_ID,
User=user, PackageBaseName=pkgbase.Name,
Comments=str(), ClosureComment=str())
PackageRequest(
ReqTypeID=MERGE_ID,
User=user,
PackageBaseName=pkgbase.Name,
Comments=str(),
ClosureComment=str(),
)
def test_package_request_null_package_base_name_raises(user: User,
pkgbase: PackageBase):
def test_package_request_null_package_base_name_raises(
user: User, pkgbase: PackageBase
):
with pytest.raises(IntegrityError):
PackageRequest(ReqTypeID=MERGE_ID,
User=user, PackageBase=pkgbase,
Comments=str(), ClosureComment=str())
PackageRequest(
ReqTypeID=MERGE_ID,
User=user,
PackageBase=pkgbase,
Comments=str(),
ClosureComment=str(),
)
def test_package_request_null_comments_raises(user: User,
pkgbase: PackageBase):
def test_package_request_null_comments_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageRequest(ReqTypeID=MERGE_ID, User=user,
PackageBase=pkgbase, PackageBaseName=pkgbase.Name,
ClosureComment=str())
PackageRequest(
ReqTypeID=MERGE_ID,
User=user,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
ClosureComment=str(),
)
def test_package_request_null_closure_comment_raises(user: User,
pkgbase: PackageBase):
def test_package_request_null_closure_comment_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageRequest(ReqTypeID=MERGE_ID, User=user,
PackageBase=pkgbase, PackageBaseName=pkgbase.Name,
Comments=str())
PackageRequest(
ReqTypeID=MERGE_ID,
User=user,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(),
)
def test_package_request_status_display(user: User, pkgbase: PackageBase):
""" Test status_display() based on the Status column value. """
"""Test status_display() based on the Status column value."""
with db.begin():
pkgreq = db.create(PackageRequest, ReqTypeID=MERGE_ID,
User=user, PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(), ClosureComment=str(),
Status=PENDING_ID)
pkgreq = db.create(
PackageRequest,
ReqTypeID=MERGE_ID,
User=user,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
Comments=str(),
ClosureComment=str(),
Status=PENDING_ID,
)
assert pkgreq.status_display() == PENDING
with db.begin():

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -18,9 +17,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd=str(),
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user
@ -34,8 +38,7 @@ def test_package_vote_creation(user: User, pkgbase: PackageBase):
ts = time.utcnow()
with db.begin():
package_vote = db.create(PackageVote, User=user,
PackageBase=pkgbase, VoteTS=ts)
package_vote = db.create(PackageVote, User=user, PackageBase=pkgbase, VoteTS=ts)
assert bool(package_vote)
assert package_vote.User == user
assert package_vote.PackageBase == pkgbase

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,4 @@
import pytest
from fastapi.testclient import TestClient
from aurweb import asgi, config, db, time
@ -23,18 +22,22 @@ def setup(db_test):
@pytest.fixture
def maintainer() -> User:
with db.begin():
maintainer = db.create(User, Username="test_maintainer",
Email="test_maintainer@examepl.org",
Passwd="testPassword",
AccountTypeID=USER_ID)
maintainer = db.create(
User,
Username="test_maintainer",
Email="test_maintainer@examepl.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield maintainer
@pytest.fixture
def package(maintainer: User) -> Package:
with db.begin():
pkgbase = db.create(PackageBase, Name="test-pkg",
Packager=maintainer, Maintainer=maintainer)
pkgbase = db.create(
PackageBase, Name="test-pkg", Packager=maintainer, Maintainer=maintainer
)
package = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
yield package
@ -51,10 +54,9 @@ def test_package_link(client: TestClient, package: Package):
def test_official_package_link(client: TestClient, package: Package):
with db.begin():
provider = db.create(OfficialProvider,
Name=package.Name,
Repo="core",
Provides=package.Name)
provider = db.create(
OfficialProvider, Name=package.Name, Repo="core", Provides=package.Name
)
expected = f"{OFFICIAL_BASE}/packages/?q={package.Name}"
assert util.package_link(provider) == expected
@ -63,9 +65,7 @@ def test_updated_packages(maintainer: User, package: Package):
expected = {
"Name": package.Name,
"Version": package.Version,
"PackageBase": {
"ModifiedTS": package.PackageBase.ModifiedTS
}
"PackageBase": {"ModifiedTS": package.PackageBase.ModifiedTS},
}
kill_redis() # Kill it here to ensure we're on a fake instance.
@ -77,8 +77,9 @@ def test_updated_packages(maintainer: User, package: Package):
def test_query_voted(maintainer: User, package: Package):
now = time.utcnow()
with db.begin():
db.create(PackageVote, User=maintainer, VoteTS=now,
PackageBase=package.PackageBase)
db.create(
PackageVote, User=maintainer, VoteTS=now, PackageBase=package.PackageBase
)
query = db.query(Package).filter(Package.ID == package.ID).all()
query_voted = util.query_voted(query, maintainer)
@ -87,8 +88,7 @@ def test_query_voted(maintainer: User, package: Package):
def test_query_notified(maintainer: User, package: Package):
with db.begin():
db.create(PackageNotification, User=maintainer,
PackageBase=package.PackageBase)
db.create(PackageNotification, User=maintainer, PackageBase=package.PackageBase)
query = db.query(Package).filter(Package.ID == package.ID).all()
query_notified = util.query_notified(query, maintainer)
@ -99,8 +99,9 @@ def test_source_uri_file(package: Package):
FILE = "test_file"
with db.begin():
pkgsrc = db.create(PackageSource, Source=FILE,
Package=package, SourceArch="x86_64")
pkgsrc = db.create(
PackageSource, Source=FILE, Package=package, SourceArch="x86_64"
)
source_file_uri = config.get("options", "source_file_uri")
file, uri = util.source_uri(pkgsrc)
expected = source_file_uri % (pkgsrc.Source, package.PackageBase.Name)
@ -112,8 +113,9 @@ def test_source_uri_named_uri(package: Package):
URL = "https://test.xyz"
with db.begin():
pkgsrc = db.create(PackageSource, Source=f"{FILE}::{URL}",
Package=package, SourceArch="x86_64")
pkgsrc = db.create(
PackageSource, Source=f"{FILE}::{URL}", Package=package, SourceArch="x86_64"
)
file, uri = util.source_uri(pkgsrc)
assert (file, uri) == (FILE, URL)
@ -122,7 +124,8 @@ def test_source_uri_unnamed_uri(package: Package):
URL = "https://test.xyz"
with db.begin():
pkgsrc = db.create(PackageSource, Source=f"{URL}",
Package=package, SourceArch="x86_64")
pkgsrc = db.create(
PackageSource, Source=f"{URL}", Package=package, SourceArch="x86_64"
)
file, uri = util.source_uri(pkgsrc)
assert (file, uri) == (URL, URL)

File diff suppressed because it is too large Load diff

View file

@ -14,8 +14,13 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
Passwd="testPassword", AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@ -26,11 +31,12 @@ def packages(user: User) -> list[Package]:
now = time.utcnow()
with db.begin():
for i in range(5):
pkgbase = db.create(PackageBase, Name=f"pkg_{i}",
SubmittedTS=now,
ModifiedTS=now)
pkg = db.create(Package, PackageBase=pkgbase,
Name=f"pkg_{i}", Version=f"{i}.0")
pkgbase = db.create(
PackageBase, Name=f"pkg_{i}", SubmittedTS=now, ModifiedTS=now
)
pkg = db.create(
Package, PackageBase=pkgbase, Name=f"pkg_{i}", Version=f"{i}.0"
)
output.append(pkg)
yield output
@ -48,7 +54,7 @@ def test_pkgmaint(packages: list[Package]):
# Modify the first package so it's out of date and gets deleted.
with db.begin():
# Reduce SubmittedTS by a day + 10 seconds.
packages[0].PackageBase.SubmittedTS -= (86400 + 10)
packages[0].PackageBase.SubmittedTS -= 86400 + 10
# Run pkgmaint.
pkgmaint.main()

View file

@ -1,7 +1,6 @@
from unittest import mock
import pytest
from redis.client import Pipeline
from aurweb import config, db, logging
@ -49,6 +48,7 @@ def mock_config_getboolean(return_value: int = 0):
if section == "ratelimit" and key == "cache":
return return_value
return config_getboolean(section, key)
return fn
@ -60,17 +60,22 @@ def mock_config_get(return_value: str = "none"):
if section == "options" and key == "cache":
return return_value
return config_get(section, key)
return fn
@mock.patch("aurweb.config.getint", side_effect=mock_config_getint)
@mock.patch("aurweb.config.getboolean", side_effect=mock_config_getboolean(1))
@mock.patch("aurweb.config.get", side_effect=mock_config_get("none"))
def test_ratelimit_redis(get: mock.MagicMock, getboolean: mock.MagicMock,
getint: mock.MagicMock, pipeline: Pipeline):
""" This test will only cover aurweb.ratelimit's Redis
def test_ratelimit_redis(
get: mock.MagicMock,
getboolean: mock.MagicMock,
getint: mock.MagicMock,
pipeline: Pipeline,
):
"""This test will only cover aurweb.ratelimit's Redis
path if a real Redis server is configured. Otherwise,
it'll use the database. """
it'll use the database."""
# We'll need a Request for everything here.
request = Request()
@ -96,8 +101,12 @@ def test_ratelimit_redis(get: mock.MagicMock, getboolean: mock.MagicMock,
@mock.patch("aurweb.config.getint", side_effect=mock_config_getint)
@mock.patch("aurweb.config.getboolean", side_effect=mock_config_getboolean(0))
@mock.patch("aurweb.config.get", side_effect=mock_config_get("none"))
def test_ratelimit_db(get: mock.MagicMock, getboolean: mock.MagicMock,
getint: mock.MagicMock, pipeline: Pipeline):
def test_ratelimit_db(
get: mock.MagicMock,
getboolean: mock.MagicMock,
getint: mock.MagicMock,
pipeline: Pipeline,
):
# We'll need a Request for everything here.
request = Request()

View file

@ -3,13 +3,13 @@ from unittest import mock
import pytest
import aurweb.config
from aurweb.redis import redis_connection
@pytest.fixture
def rediss():
""" Create a RedisStub. """
"""Create a RedisStub."""
def mock_get(section, key):
return "none"

View file

@ -31,8 +31,13 @@ def setup(db_test, git: GitRepository):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
Passwd=str(), AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user
@ -40,24 +45,32 @@ def user() -> User:
def pkgbase(user: User) -> PackageBase:
now = time.utcnow()
with db.begin():
pkgbase = db.create(PackageBase, Packager=user, Name="pkgbase_0",
SubmittedTS=now, ModifiedTS=now)
pkgbase = db.create(
PackageBase,
Packager=user,
Name="pkgbase_0",
SubmittedTS=now,
ModifiedTS=now,
)
yield pkgbase
@pytest.fixture
def package(pkgbase: PackageBase) -> Package:
with db.begin():
package = db.create(Package, PackageBase=pkgbase,
Name=pkgbase.Name, Version="1.0")
package = db.create(
Package, PackageBase=pkgbase, Name=pkgbase.Name, Version="1.0"
)
yield package
def create_comment(user: User, pkgbase: PackageBase, comments: str,
render: bool = True):
def create_comment(
user: User, pkgbase: PackageBase, comments: str, render: bool = True
):
with db.begin():
comment = db.create(PackageComment, User=user,
PackageBase=pkgbase, Comments=comments)
comment = db.create(
PackageComment, User=user, PackageBase=pkgbase, Comments=comments
)
if render:
update_comment_render(comment)
return comment
@ -86,8 +99,7 @@ def test_rendercomment_main(user: User, pkgbase: PackageBase):
def test_markdown_conversion(user: User, pkgbase: PackageBase):
text = "*Hello* [world](https://aur.archlinux.org)!"
comment = create_comment(user, pkgbase, text)
expected = ('<p><em>Hello</em> '
'<a href="https://aur.archlinux.org">world</a>!</p>')
expected = "<p><em>Hello</em> " '<a href="https://aur.archlinux.org">world</a>!</p>'
assert comment.RenderedComment == expected
@ -109,7 +121,7 @@ Visit [Arch Linux][arch].
[arch]: https://www.archlinux.org/\
"""
comment = create_comment(user, pkgbase, text)
expected = '''\
expected = """\
<p>Visit <a href="https://www.archlinux.org/#_test_">\
https://www.archlinux.org/#_test_</a>.
Visit <em><a href="https://www.archlinux.org/">https://www.archlinux.org/</a></em>.
@ -117,7 +129,7 @@ Visit <a href="https://www.archlinux.org/">https://www.archlinux.org/</a>.
Visit <code>https://www.archlinux.org/</code>.
Visit <a href="https://www.archlinux.org/">Arch Linux</a>.
Visit <a href="https://www.archlinux.org/">Arch Linux</a>.</p>\
'''
"""
assert comment.RenderedComment == expected

View file

@ -1,10 +1,8 @@
import re
from http import HTTPStatus
from logging import DEBUG
import pytest
from fastapi import HTTPException
from fastapi.testclient import TestClient
@ -24,13 +22,13 @@ from aurweb.testing.requests import Request
@pytest.fixture(autouse=True)
def setup(db_test) -> None:
""" Setup the database. """
"""Setup the database."""
return
@pytest.fixture
def client() -> TestClient:
""" Yield a TestClient. """
"""Yield a TestClient."""
yield TestClient(app=asgi.app)
@ -43,21 +41,26 @@ def create_user(username: str, email: str) -> User:
:return: User instance
"""
with db.begin():
user = db.create(User, Username=username, Email=email,
Passwd="testPassword", AccountTypeID=USER_ID)
user = db.create(
User,
Username=username,
Email=email,
Passwd="testPassword",
AccountTypeID=USER_ID,
)
return user
@pytest.fixture
def user() -> User:
""" Yield a User instance. """
"""Yield a User instance."""
user = create_user("test", "test@example.org")
yield user
@pytest.fixture
def auser(user: User) -> User:
""" Yield an authenticated User instance. """
"""Yield an authenticated User instance."""
cookies = {"AURSID": user.login(Request(), "testPassword")}
user.cookies = cookies
yield user
@ -65,14 +68,14 @@ def auser(user: User) -> User:
@pytest.fixture
def user2() -> User:
""" Yield a secondary non-maintainer User instance. """
"""Yield a secondary non-maintainer User instance."""
user = create_user("test2", "test2@example.org")
yield user
@pytest.fixture
def auser2(user2: User) -> User:
""" Yield an authenticated secondary non-maintainer User instance. """
"""Yield an authenticated secondary non-maintainer User instance."""
cookies = {"AURSID": user2.login(Request(), "testPassword")}
user2.cookies = cookies
yield user2
@ -80,31 +83,34 @@ def auser2(user2: User) -> User:
@pytest.fixture
def maintainer() -> User:
""" Yield a specific User used to maintain packages. """
"""Yield a specific User used to maintain packages."""
with db.begin():
maintainer = db.create(User, Username="test_maintainer",
Email="test_maintainer@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID)
maintainer = db.create(
User,
Username="test_maintainer",
Email="test_maintainer@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield maintainer
@pytest.fixture
def packages(maintainer: User) -> list[Package]:
""" Yield 55 packages named pkg_0 .. pkg_54. """
"""Yield 55 packages named pkg_0 .. pkg_54."""
packages_ = []
now = time.utcnow()
with db.begin():
for i in range(55):
pkgbase = db.create(PackageBase,
Name=f"pkg_{i}",
Maintainer=maintainer,
Packager=maintainer,
Submitter=maintainer,
ModifiedTS=now)
package = db.create(Package,
PackageBase=pkgbase,
Name=f"pkg_{i}")
pkgbase = db.create(
PackageBase,
Name=f"pkg_{i}",
Maintainer=maintainer,
Packager=maintainer,
Submitter=maintainer,
ModifiedTS=now,
)
package = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}")
packages_.append(package)
yield packages_
@ -115,20 +121,22 @@ def requests(user: User, packages: list[Package]) -> list[PackageRequest]:
pkgreqs = []
with db.begin():
for i in range(55):
pkgreq = db.create(PackageRequest,
ReqTypeID=DELETION_ID,
User=user,
PackageBase=packages[i].PackageBase,
PackageBaseName=packages[i].Name,
Comments=f"Deletion request for pkg_{i}",
ClosureComment=str())
pkgreq = db.create(
PackageRequest,
ReqTypeID=DELETION_ID,
User=user,
PackageBase=packages[i].PackageBase,
PackageBaseName=packages[i].Name,
Comments=f"Deletion request for pkg_{i}",
ClosureComment=str(),
)
pkgreqs.append(pkgreq)
yield pkgreqs
@pytest.fixture
def tu_user() -> User:
""" Yield an authenticated Trusted User instance. """
"""Yield an authenticated Trusted User instance."""
user = create_user("test_tu", "test_tu@example.org")
with db.begin():
user.AccountTypeID = TRUSTED_USER_ID
@ -149,31 +157,38 @@ def create_pkgbase(user: User, name: str) -> PackageBase:
"""
now = time.utcnow()
with db.begin():
pkgbase = db.create(PackageBase, Name=name,
Maintainer=user, Packager=user,
SubmittedTS=now, ModifiedTS=now)
pkgbase = db.create(
PackageBase,
Name=name,
Maintainer=user,
Packager=user,
SubmittedTS=now,
ModifiedTS=now,
)
db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
return pkgbase
@pytest.fixture
def pkgbase(user: User) -> PackageBase:
""" Yield a package base. """
"""Yield a package base."""
pkgbase = create_pkgbase(user, "test-package")
yield pkgbase
@pytest.fixture
def target(user: User) -> PackageBase:
""" Yield a merge target (package base). """
"""Yield a merge target (package base)."""
with db.begin():
target = db.create(PackageBase, Name="target-package",
Maintainer=user, Packager=user)
target = db.create(
PackageBase, Name="target-package", Maintainer=user, Packager=user
)
yield target
def create_request(reqtype_id: int, user: User, pkgbase: PackageBase,
comments: str) -> PackageRequest:
def create_request(
reqtype_id: int, user: User, pkgbase: PackageBase, comments: str
) -> PackageRequest:
"""
Create a package request based on `reqtype_id`, `user`,
`pkgbase` and `comments`.
@ -186,40 +201,43 @@ def create_request(reqtype_id: int, user: User, pkgbase: PackageBase,
"""
now = time.utcnow()
with db.begin():
pkgreq = db.create(PackageRequest, ReqTypeID=reqtype_id,
User=user, PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
RequestTS=now,
Comments=comments,
ClosureComment=str())
pkgreq = db.create(
PackageRequest,
ReqTypeID=reqtype_id,
User=user,
PackageBase=pkgbase,
PackageBaseName=pkgbase.Name,
RequestTS=now,
Comments=comments,
ClosureComment=str(),
)
return pkgreq
@pytest.fixture
def pkgreq(user: User, pkgbase: PackageBase):
""" Yield a package request. """
"""Yield a package request."""
pkgreq = create_request(DELETION_ID, user, pkgbase, "Test request.")
yield pkgreq
def create_notification(user: User, pkgbase: PackageBase):
""" Create a notification for a `user` on `pkgbase`. """
"""Create a notification for a `user` on `pkgbase`."""
with db.begin():
notif = db.create(PackageNotification, User=user, PackageBase=pkgbase)
return notif
def test_request(client: TestClient, auser: User, pkgbase: PackageBase):
""" Test the standard pkgbase request route GET method. """
"""Test the standard pkgbase request route GET method."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
with client as request:
resp = request.get(endpoint, cookies=auser.cookies)
assert resp.status_code == int(HTTPStatus.OK)
def test_request_post_deletion(client: TestClient, auser2: User,
pkgbase: PackageBase):
""" Test the POST route for creating a deletion request works. """
def test_request_post_deletion(client: TestClient, auser2: User, pkgbase: PackageBase):
"""Test the POST route for creating a deletion request works."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {"comments": "Test request.", "type": "deletion"}
with client as request:
@ -238,9 +256,10 @@ def test_request_post_deletion(client: TestClient, auser2: User,
assert re.match(expr, email.headers.get("Subject"))
def test_request_post_deletion_as_maintainer(client: TestClient, auser: User,
pkgbase: PackageBase):
""" Test the POST route for creating a deletion request as maint works. """
def test_request_post_deletion_as_maintainer(
client: TestClient, auser: User, pkgbase: PackageBase
):
"""Test the POST route for creating a deletion request as maint works."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {"comments": "Test request.", "type": "deletion"}
with client as request:
@ -267,10 +286,13 @@ def test_request_post_deletion_as_maintainer(client: TestClient, auser: User,
assert re.match(expr, email.headers.get("Subject"))
def test_request_post_deletion_autoaccept(client: TestClient, auser: User,
pkgbase: PackageBase,
caplog: pytest.LogCaptureFixture):
""" Test the request route for deletion as maintainer. """
def test_request_post_deletion_autoaccept(
client: TestClient,
auser: User,
pkgbase: PackageBase,
caplog: pytest.LogCaptureFixture,
):
"""Test the request route for deletion as maintainer."""
caplog.set_level(DEBUG)
now = time.utcnow()
@ -284,9 +306,11 @@ def test_request_post_deletion_autoaccept(client: TestClient, auser: User,
resp = request.post(endpoint, data=data, cookies=auser.cookies)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
pkgreq = db.query(PackageRequest).filter(
PackageRequest.PackageBaseName == pkgbase.Name
).first()
pkgreq = (
db.query(PackageRequest)
.filter(PackageRequest.PackageBaseName == pkgbase.Name)
.first()
)
assert pkgreq is not None
assert pkgreq.ReqTypeID == DELETION_ID
assert pkgreq.Status == ACCEPTED_ID
@ -310,9 +334,10 @@ def test_request_post_deletion_autoaccept(client: TestClient, auser: User,
assert re.search(expr, caplog.text)
def test_request_post_merge(client: TestClient, auser: User,
pkgbase: PackageBase, target: PackageBase):
""" Test the request route for merge as maintainer. """
def test_request_post_merge(
client: TestClient, auser: User, pkgbase: PackageBase, target: PackageBase
):
"""Test the request route for merge as maintainer."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {
"type": "merge",
@ -336,9 +361,8 @@ def test_request_post_merge(client: TestClient, auser: User,
assert re.match(expr, email.headers.get("Subject"))
def test_request_post_orphan(client: TestClient, auser: User,
pkgbase: PackageBase):
""" Test the POST route for creating an orphan request works. """
def test_request_post_orphan(client: TestClient, auser: User, pkgbase: PackageBase):
"""Test the POST route for creating an orphan request works."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {
"type": "orphan",
@ -361,9 +385,14 @@ def test_request_post_orphan(client: TestClient, auser: User,
assert re.match(expr, email.headers.get("Subject"))
def test_deletion_request(client: TestClient, user: User, tu_user: User,
pkgbase: PackageBase, pkgreq: PackageRequest):
""" Test deleting a package with a preexisting request. """
def test_deletion_request(
client: TestClient,
user: User,
tu_user: User,
pkgbase: PackageBase,
pkgreq: PackageRequest,
):
"""Test deleting a package with a preexisting request."""
# `pkgreq`.ReqTypeID is already DELETION_ID.
create_request(DELETION_ID, user, pkgbase, "Other request.")
@ -402,9 +431,8 @@ def test_deletion_request(client: TestClient, user: User, tu_user: User,
assert body in email.body
def test_deletion_autorequest(client: TestClient, tu_user: User,
pkgbase: PackageBase):
""" Test deleting a package without a request. """
def test_deletion_autorequest(client: TestClient, tu_user: User, pkgbase: PackageBase):
"""Test deleting a package without a request."""
# `pkgreq`.ReqTypeID is already DELETION_ID.
endpoint = f"/pkgbase/{pkgbase.Name}/delete"
data = {"confirm": True}
@ -421,10 +449,15 @@ def test_deletion_autorequest(client: TestClient, tu_user: User,
assert "[Autogenerated]" in email.body
def test_merge_request(client: TestClient, user: User, tu_user: User,
pkgbase: PackageBase, target: PackageBase,
pkgreq: PackageRequest):
""" Test merging a package with a pre - existing request. """
def test_merge_request(
client: TestClient,
user: User,
tu_user: User,
pkgbase: PackageBase,
target: PackageBase,
pkgreq: PackageRequest,
):
"""Test merging a package with a pre - existing request."""
with db.begin():
pkgreq.ReqTypeID = MERGE_ID
pkgreq.MergeBaseName = target.Name
@ -473,9 +506,14 @@ def test_merge_request(client: TestClient, user: User, tu_user: User,
assert "[Autogenerated]" in rejected.body
def test_merge_autorequest(client: TestClient, user: User, tu_user: User,
pkgbase: PackageBase, target: PackageBase):
""" Test merging a package without a request. """
def test_merge_autorequest(
client: TestClient,
user: User,
tu_user: User,
pkgbase: PackageBase,
target: PackageBase,
):
"""Test merging a package without a request."""
with db.begin():
pkgreq.ReqTypeID = MERGE_ID
pkgreq.MergeBaseName = target.Name
@ -498,13 +536,17 @@ def test_merge_autorequest(client: TestClient, user: User, tu_user: User,
assert "[Autogenerated]" in email.body
def test_orphan_request(client: TestClient, user: User, tu_user: User,
pkgbase: PackageBase, pkgreq: PackageRequest):
""" Test the standard orphan request route. """
def test_orphan_request(
client: TestClient,
user: User,
tu_user: User,
pkgbase: PackageBase,
pkgreq: PackageRequest,
):
"""Test the standard orphan request route."""
user2 = create_user("user2", "user2@example.org")
with db.begin():
db.create(PackageComaintainer, User=user2,
PackageBase=pkgbase, Priority=1)
db.create(PackageComaintainer, User=user2, PackageBase=pkgbase, Priority=1)
idle_time = config.getint("options", "request_idle_time")
now = time.utcnow()
@ -537,10 +579,9 @@ def test_orphan_request(client: TestClient, user: User, tu_user: User,
assert re.match(subj, email.headers.get("Subject"))
def test_request_post_orphan_autogenerated_closure(client: TestClient,
tu_user: User,
pkgbase: PackageBase,
pkgreq: PackageRequest):
def test_request_post_orphan_autogenerated_closure(
client: TestClient, tu_user: User, pkgbase: PackageBase, pkgreq: PackageRequest
):
idle_time = config.getint("options", "request_idle_time")
now = time.utcnow()
with db.begin():
@ -564,10 +605,13 @@ def test_request_post_orphan_autogenerated_closure(client: TestClient,
assert re.search(expr, email.body)
def test_request_post_orphan_autoaccept(client: TestClient, auser: User,
pkgbase: PackageBase,
caplog: pytest.LogCaptureFixture):
""" Test the standard pkgbase request route GET method. """
def test_request_post_orphan_autoaccept(
client: TestClient,
auser: User,
pkgbase: PackageBase,
caplog: pytest.LogCaptureFixture,
):
"""Test the standard pkgbase request route GET method."""
caplog.set_level(DEBUG)
now = time.utcnow()
auto_orphan_age = config.getint("options", "auto_orphan_age")
@ -605,8 +649,7 @@ def test_request_post_orphan_autoaccept(client: TestClient, auser: User,
assert re.search(expr, caplog.text)
def test_orphan_as_maintainer(client: TestClient, auser: User,
pkgbase: PackageBase):
def test_orphan_as_maintainer(client: TestClient, auser: User, pkgbase: PackageBase):
endpoint = f"/pkgbase/{pkgbase.Name}/disown"
data = {"confirm": True}
with client as request:
@ -620,9 +663,10 @@ def test_orphan_as_maintainer(client: TestClient, auser: User,
assert pkgbase.Maintainer is None
def test_orphan_without_requests(client: TestClient, tu_user: User,
pkgbase: PackageBase):
""" Test orphans are automatically accepted past a certain date. """
def test_orphan_without_requests(
client: TestClient, tu_user: User, pkgbase: PackageBase
):
"""Test orphans are automatically accepted past a certain date."""
endpoint = f"/pkgbase/{pkgbase.Name}/disown"
data = {"confirm": True}
with client as request:
@ -637,7 +681,7 @@ def test_orphan_without_requests(client: TestClient, tu_user: User,
def test_closure_factory_invalid_reqtype_id():
""" Test providing an invalid reqtype_id raises NotImplementedError. """
"""Test providing an invalid reqtype_id raises NotImplementedError."""
automated = ClosureFactory()
match = r"^Unsupported '.+' value\.$"
with pytest.raises(NotImplementedError, match=match):
@ -657,19 +701,25 @@ def test_requests_unauthorized(client: TestClient):
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
def test_requests(client: TestClient,
tu_user: User,
packages: list[Package],
requests: list[PackageRequest]):
def test_requests(
client: TestClient,
tu_user: User,
packages: list[Package],
requests: list[PackageRequest],
):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
resp = request.get("/requests", params={
# Pass in url query parameters O, SeB and SB to exercise
# their paths inside of the pager_nav used in this request.
"O": 0, # Page 1
"SeB": "nd",
"SB": "n"
}, cookies=cookies)
resp = request.get(
"/requests",
params={
# Pass in url query parameters O, SeB and SB to exercise
# their paths inside of the pager_nav used in this request.
"O": 0, # Page 1
"SeB": "nd",
"SB": "n",
},
cookies=cookies,
)
assert resp.status_code == int(HTTPStatus.OK)
assert "Next " in resp.text
@ -682,9 +732,7 @@ def test_requests(client: TestClient,
# Request page 2 of the requests page.
with client as request:
resp = request.get("/requests", params={
"O": 50 # Page 2
}, cookies=cookies)
resp = request.get("/requests", params={"O": 50}, cookies=cookies) # Page 2
assert resp.status_code == int(HTTPStatus.OK)
assert " Previous" in resp.text
@ -695,8 +743,9 @@ def test_requests(client: TestClient,
assert len(rows) == 5 # There are five records left on the second page.
def test_requests_selfmade(client: TestClient, user: User,
requests: list[PackageRequest]):
def test_requests_selfmade(
client: TestClient, user: User, requests: list[PackageRequest]
):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.get("/requests", cookies=cookies)
@ -710,46 +759,52 @@ def test_requests_selfmade(client: TestClient, user: User,
# Our first and only link in the last row should be "Close".
for row in rows:
last_row = row.xpath('./td')[-1].xpath('./a')[0]
last_row = row.xpath("./td")[-1].xpath("./a")[0]
assert last_row.text.strip() == "Close"
def test_requests_close(client: TestClient, user: User,
pkgreq: PackageRequest):
def test_requests_close(client: TestClient, user: User, pkgreq: PackageRequest):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies,
allow_redirects=False)
resp = request.get(
f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
)
assert resp.status_code == int(HTTPStatus.OK)
def test_requests_close_unauthorized(client: TestClient, maintainer: User,
pkgreq: PackageRequest):
def test_requests_close_unauthorized(
client: TestClient, maintainer: User, pkgreq: PackageRequest
):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies,
allow_redirects=False)
resp = request.get(
f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == "/"
def test_requests_close_post_unauthorized(client: TestClient, maintainer: User,
pkgreq: PackageRequest):
def test_requests_close_post_unauthorized(
client: TestClient, maintainer: User, pkgreq: PackageRequest
):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
resp = request.post(f"/requests/{pkgreq.ID}/close", data={
"reason": ACCEPTED_ID
}, cookies=cookies, allow_redirects=False)
resp = request.post(
f"/requests/{pkgreq.ID}/close",
data={"reason": ACCEPTED_ID},
cookies=cookies,
allow_redirects=False,
)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == "/"
def test_requests_close_post(client: TestClient, user: User,
pkgreq: PackageRequest):
def test_requests_close_post(client: TestClient, user: User, pkgreq: PackageRequest):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.post(f"/requests/{pkgreq.ID}/close",
cookies=cookies, allow_redirects=False)
resp = request.post(
f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert pkgreq.Status == REJECTED_ID
@ -757,12 +812,14 @@ def test_requests_close_post(client: TestClient, user: User,
assert pkgreq.ClosureComment == str()
def test_requests_close_post_rejected(client: TestClient, user: User,
pkgreq: PackageRequest):
def test_requests_close_post_rejected(
client: TestClient, user: User, pkgreq: PackageRequest
):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.post(f"/requests/{pkgreq.ID}/close",
cookies=cookies, allow_redirects=False)
resp = request.post(
f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert pkgreq.Status == REJECTED_ID

View file

@ -1,11 +1,9 @@
import re
import urllib.parse
from http import HTTPStatus
import lxml.etree
import pytest
from fastapi.testclient import TestClient
from aurweb import db
@ -28,21 +26,26 @@ def client() -> TestClient:
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
def test_index(client: TestClient):
""" Test the index route at '/'. """
"""Test the index route at '/'."""
with client as req:
response = req.get("/")
assert response.status_code == int(HTTPStatus.OK)
def test_index_security_headers(client: TestClient):
""" Check for the existence of CSP, XCTO, XFO and RP security headers.
"""Check for the existence of CSP, XCTO, XFO and RP security headers.
CSP: Content-Security-Policy
XCTO: X-Content-Type-Options
@ -60,7 +63,7 @@ def test_index_security_headers(client: TestClient):
def test_favicon(client: TestClient):
""" Test the favicon route at '/favicon.ico'. """
"""Test the favicon route at '/favicon.ico'."""
with client as request:
response1 = request.get("/static/images/favicon.ico")
response2 = request.get("/favicon.ico")
@ -69,52 +72,38 @@ def test_favicon(client: TestClient):
def test_language(client: TestClient):
""" Test the language post route as a guest user. """
post_data = {
"set_lang": "de",
"next": "/"
}
"""Test the language post route as a guest user."""
post_data = {"set_lang": "de", "next": "/"}
with client as req:
response = req.post("/language", data=post_data)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
def test_language_invalid_next(client: TestClient):
""" Test an invalid next route at '/language'. """
post_data = {
"set_lang": "de",
"next": "https://evil.net"
}
"""Test an invalid next route at '/language'."""
post_data = {"set_lang": "de", "next": "https://evil.net"}
with client as req:
response = req.post("/language", data=post_data)
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
def test_user_language(client: TestClient, user: User):
""" Test the language post route as an authenticated user. """
post_data = {
"set_lang": "de",
"next": "/"
}
"""Test the language post route as an authenticated user."""
post_data = {"set_lang": "de", "next": "/"}
sid = user.login(Request(), "testPassword")
assert sid is not None
with client as req:
response = req.post("/language", data=post_data,
cookies={"AURSID": sid})
response = req.post("/language", data=post_data, cookies={"AURSID": sid})
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert user.LangPreference == "de"
def test_language_query_params(client: TestClient):
""" Test the language post route with query params. """
"""Test the language post route with query params."""
next = urllib.parse.quote_plus("/")
post_data = {
"set_lang": "de",
"next": "/",
"q": f"next={next}"
}
post_data = {"set_lang": "de", "next": "/", "q": f"next={next}"}
q = post_data.get("q")
with client as req:
response = req.post("/language", data=post_data)
@ -154,9 +143,13 @@ def test_nonce_csp(client: TestClient):
def test_id_redirect(client: TestClient):
with client as request:
response = request.get("/", params={
"id": "test", # This param will be rewritten into Location.
"key": "value", # Test that this param persists.
"key2": "value2" # And this one.
}, allow_redirects=False)
response = request.get(
"/",
params={
"id": "test", # This param will be rewritten into Location.
"key": "value", # Test that this param persists.
"key2": "value2", # And this one.
},
allow_redirects=False,
)
assert response.headers.get("location") == "/test?key=value&key2=value2"

View file

@ -1,17 +1,14 @@
import re
from http import HTTPStatus
from unittest import mock
import orjson
import pytest
from fastapi.testclient import TestClient
from redis.client import Pipeline
import aurweb.models.dependency_type as dt
import aurweb.models.relation_type as rt
from aurweb import asgi, config, db, rpc, scripts, time
from aurweb.models.account_type import USER_ID
from aurweb.models.dependency_type import DEPENDS_ID
@ -36,27 +33,42 @@ def client() -> TestClient:
@pytest.fixture
def user(db_test) -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User 1", Passwd=str(),
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User 1",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def user2() -> User:
with db.begin():
user = db.create(User, Username="user2", Email="user2@example.org",
RealName="Test User 2", Passwd=str(),
AccountTypeID=USER_ID)
user = db.create(
User,
Username="user2",
Email="user2@example.org",
RealName="Test User 2",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def user3() -> User:
with db.begin():
user = db.create(User, Username="user3", Email="user3@example.org",
RealName="Test User 3", Passwd=str(),
AccountTypeID=USER_ID)
user = db.create(
User,
Username="user3",
Email="user3@example.org",
RealName="Test User 3",
Passwd=str(),
AccountTypeID=USER_ID,
)
yield user
@ -66,39 +78,64 @@ def packages(user: User, user2: User, user3: User) -> list[Package]:
# Create package records used in our tests.
with db.begin():
pkgbase = db.create(PackageBase, Name="big-chungus",
Maintainer=user, Packager=user)
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
Description="Bunny bunny around bunny",
URL="https://example.com/")
pkgbase = db.create(
PackageBase, Name="big-chungus", Maintainer=user, Packager=user
)
pkg = db.create(
Package,
PackageBase=pkgbase,
Name=pkgbase.Name,
Description="Bunny bunny around bunny",
URL="https://example.com/",
)
output.append(pkg)
pkgbase = db.create(PackageBase, Name="chungy-chungus",
Maintainer=user, Packager=user)
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
Description="Wubby wubby on wobba wuubu",
URL="https://example.com/")
pkgbase = db.create(
PackageBase, Name="chungy-chungus", Maintainer=user, Packager=user
)
pkg = db.create(
Package,
PackageBase=pkgbase,
Name=pkgbase.Name,
Description="Wubby wubby on wobba wuubu",
URL="https://example.com/",
)
output.append(pkg)
pkgbase = db.create(PackageBase, Name="gluggly-chungus",
Maintainer=user, Packager=user)
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
Description="glurrba glurrba gur globba",
URL="https://example.com/")
pkgbase = db.create(
PackageBase, Name="gluggly-chungus", Maintainer=user, Packager=user
)
pkg = db.create(
Package,
PackageBase=pkgbase,
Name=pkgbase.Name,
Description="glurrba glurrba gur globba",
URL="https://example.com/",
)
output.append(pkg)
pkgbase = db.create(PackageBase, Name="fugly-chungus",
Maintainer=user, Packager=user)
pkgbase = db.create(
PackageBase, Name="fugly-chungus", Maintainer=user, Packager=user
)
desc = "A Package belonging to a PackageBase with another name."
pkg = db.create(Package, PackageBase=pkgbase, Name="other-pkg",
Description=desc, URL="https://example.com")
pkg = db.create(
Package,
PackageBase=pkgbase,
Name="other-pkg",
Description=desc,
URL="https://example.com",
)
output.append(pkg)
pkgbase = db.create(PackageBase, Name="woogly-chungus")
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
Description="wuggla woblabeloop shemashmoop",
URL="https://example.com/")
pkg = db.create(
Package,
PackageBase=pkgbase,
Name=pkgbase.Name,
Description="wuggla woblabeloop shemashmoop",
URL="https://example.com/",
)
output.append(pkg)
# Setup a few more related records on the first package:
@ -108,14 +145,15 @@ def packages(user: User, user2: User, user3: User) -> list[Package]:
db.create(PackageLicense, Package=output[0], License=lic)
for keyword in ["big-chungus", "smol-chungus", "sizeable-chungus"]:
db.create(PackageKeyword,
PackageBase=output[0].PackageBase,
Keyword=keyword)
db.create(
PackageKeyword, PackageBase=output[0].PackageBase, Keyword=keyword
)
now = time.utcnow()
for user_ in [user, user2, user3]:
db.create(PackageVote, User=user_,
PackageBase=output[0].PackageBase, VoteTS=now)
db.create(
PackageVote, User=user_, PackageBase=output[0].PackageBase, VoteTS=now
)
scripts.popupdate.run_single(output[0].PackageBase)
yield output
@ -126,35 +164,45 @@ def depends(packages: list[Package]) -> list[PackageDependency]:
output = []
with db.begin():
dep = db.create(PackageDependency,
Package=packages[0],
DepTypeID=dt.DEPENDS_ID,
DepName="chungus-depends")
dep = db.create(
PackageDependency,
Package=packages[0],
DepTypeID=dt.DEPENDS_ID,
DepName="chungus-depends",
)
output.append(dep)
dep = db.create(PackageDependency,
Package=packages[1],
DepTypeID=dt.DEPENDS_ID,
DepName="chungy-depends")
dep = db.create(
PackageDependency,
Package=packages[1],
DepTypeID=dt.DEPENDS_ID,
DepName="chungy-depends",
)
output.append(dep)
dep = db.create(PackageDependency,
Package=packages[0],
DepTypeID=dt.OPTDEPENDS_ID,
DepName="chungus-optdepends",
DepCondition="=50")
dep = db.create(
PackageDependency,
Package=packages[0],
DepTypeID=dt.OPTDEPENDS_ID,
DepName="chungus-optdepends",
DepCondition="=50",
)
output.append(dep)
dep = db.create(PackageDependency,
Package=packages[0],
DepTypeID=dt.MAKEDEPENDS_ID,
DepName="chungus-makedepends")
dep = db.create(
PackageDependency,
Package=packages[0],
DepTypeID=dt.MAKEDEPENDS_ID,
DepName="chungus-makedepends",
)
output.append(dep)
dep = db.create(PackageDependency,
Package=packages[0],
DepTypeID=dt.CHECKDEPENDS_ID,
DepName="chungus-checkdepends")
dep = db.create(
PackageDependency,
Package=packages[0],
DepTypeID=dt.CHECKDEPENDS_ID,
DepName="chungus-checkdepends",
)
output.append(dep)
yield output
@ -165,30 +213,38 @@ def relations(user: User, packages: list[Package]) -> list[PackageRelation]:
output = []
with db.begin():
rel = db.create(PackageRelation,
Package=packages[0],
RelTypeID=rt.CONFLICTS_ID,
RelName="chungus-conflicts")
rel = db.create(
PackageRelation,
Package=packages[0],
RelTypeID=rt.CONFLICTS_ID,
RelName="chungus-conflicts",
)
output.append(rel)
rel = db.create(PackageRelation,
Package=packages[1],
RelTypeID=rt.CONFLICTS_ID,
RelName="chungy-conflicts")
rel = db.create(
PackageRelation,
Package=packages[1],
RelTypeID=rt.CONFLICTS_ID,
RelName="chungy-conflicts",
)
output.append(rel)
rel = db.create(PackageRelation,
Package=packages[0],
RelTypeID=rt.PROVIDES_ID,
RelName="chungus-provides",
RelCondition="<=200")
rel = db.create(
PackageRelation,
Package=packages[0],
RelTypeID=rt.PROVIDES_ID,
RelName="chungus-provides",
RelCondition="<=200",
)
output.append(rel)
rel = db.create(PackageRelation,
Package=packages[0],
RelTypeID=rt.REPLACES_ID,
RelName="chungus-replaces",
RelCondition="<=200")
rel = db.create(
PackageRelation,
Package=packages[0],
RelTypeID=rt.REPLACES_ID,
RelName="chungus-replaces",
RelCondition="<=200",
)
output.append(rel)
# Finally, yield the packages.
@ -238,51 +294,54 @@ def test_rpc_documentation_missing():
config.rehash()
def test_rpc_singular_info(client: TestClient,
user: User,
packages: list[Package],
depends: list[PackageDependency],
relations: list[PackageRelation]):
def test_rpc_singular_info(
client: TestClient,
user: User,
packages: list[Package],
depends: list[PackageDependency],
relations: list[PackageRelation],
):
# Define expected response.
pkg = packages[0]
expected_data = {
"version": 5,
"results": [{
"Name": pkg.Name,
"Version": pkg.Version,
"Description": pkg.Description,
"URL": pkg.URL,
"PackageBase": pkg.PackageBase.Name,
"NumVotes": pkg.PackageBase.NumVotes,
"Popularity": float(pkg.PackageBase.Popularity),
"OutOfDate": None,
"Maintainer": user.Username,
"URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz",
"Depends": ["chungus-depends"],
"OptDepends": ["chungus-optdepends=50"],
"MakeDepends": ["chungus-makedepends"],
"CheckDepends": ["chungus-checkdepends"],
"Conflicts": ["chungus-conflicts"],
"Provides": ["chungus-provides<=200"],
"Replaces": ["chungus-replaces<=200"],
"License": [pkg.package_licenses.first().License.Name],
"Keywords": [
"big-chungus",
"sizeable-chungus",
"smol-chungus"
]
}],
"results": [
{
"Name": pkg.Name,
"Version": pkg.Version,
"Description": pkg.Description,
"URL": pkg.URL,
"PackageBase": pkg.PackageBase.Name,
"NumVotes": pkg.PackageBase.NumVotes,
"Popularity": float(pkg.PackageBase.Popularity),
"OutOfDate": None,
"Maintainer": user.Username,
"URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz",
"Depends": ["chungus-depends"],
"OptDepends": ["chungus-optdepends=50"],
"MakeDepends": ["chungus-makedepends"],
"CheckDepends": ["chungus-checkdepends"],
"Conflicts": ["chungus-conflicts"],
"Provides": ["chungus-provides<=200"],
"Replaces": ["chungus-replaces<=200"],
"License": [pkg.package_licenses.first().License.Name],
"Keywords": ["big-chungus", "sizeable-chungus", "smol-chungus"],
}
],
"resultcount": 1,
"type": "multiinfo"
"type": "multiinfo",
}
# Make dummy request.
with client as request:
resp = request.get("/rpc", params={
"v": 5,
"type": "info",
"arg": ["chungy-chungus", "big-chungus"],
})
resp = request.get(
"/rpc",
params={
"v": 5,
"type": "info",
"arg": ["chungy-chungus", "big-chungus"],
},
)
# Load request response into Python dictionary.
response_data = orjson.loads(resp.text)
@ -299,19 +358,21 @@ def test_rpc_singular_info(client: TestClient,
def test_rpc_split_package_urlpath(client: TestClient, user: User):
with db.begin():
pkgbase = db.create(PackageBase, Name="pkg",
Maintainer=user, Packager=user)
pkgbase = db.create(PackageBase, Name="pkg", Maintainer=user, Packager=user)
pkgs = [
db.create(Package, PackageBase=pkgbase, Name="pkg_1"),
db.create(Package, PackageBase=pkgbase, Name="pkg_2"),
]
with client as request:
response = request.get("/rpc", params={
"v": 5,
"type": "info",
"arg": [pkgs[0].Name],
})
response = request.get(
"/rpc",
params={
"v": 5,
"type": "info",
"arg": [pkgs[0].Name],
},
)
data = orjson.loads(response.text)
snapshot_uri = config.get("options", "snapshot_uri")
@ -335,9 +396,9 @@ def test_rpc_multiinfo(client: TestClient, packages: list[Package]):
# Make dummy request.
request_packages = ["big-chungus", "chungy-chungus"]
with client as request:
response = request.get("/rpc", params={
"v": 5, "type": "info", "arg[]": request_packages
})
response = request.get(
"/rpc", params={"v": 5, "type": "info", "arg[]": request_packages}
)
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@ -357,13 +418,15 @@ def test_rpc_mixedargs(client: TestClient, packages: list[Package]):
with client as request:
# Supply all of the args in the url to enforce ordering.
response1 = request.get(
"/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info")
"/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info"
)
assert response1.status_code == int(HTTPStatus.OK)
with client as request:
response2 = request.get(
"/rpc?v=5&arg=big-chungus&arg[]=gluggly-chungus"
"&type=info&arg[]=chungy-chungus")
"&type=info&arg[]=chungy-chungus"
)
assert response1.status_code == int(HTTPStatus.OK)
# Load request response into Python dictionary.
@ -381,42 +444,47 @@ def test_rpc_mixedargs(client: TestClient, packages: list[Package]):
assert i == []
def test_rpc_no_dependencies_omits_key(client: TestClient, user: User,
packages: list[Package],
depends: list[PackageDependency],
relations: list[PackageRelation]):
def test_rpc_no_dependencies_omits_key(
client: TestClient,
user: User,
packages: list[Package],
depends: list[PackageDependency],
relations: list[PackageRelation],
):
"""
This makes sure things like 'MakeDepends' get removed from JSON strings
when they don't have set values.
"""
pkg = packages[1]
expected_response = {
'version': 5,
'results': [{
'Name': pkg.Name,
'Version': pkg.Version,
'Description': pkg.Description,
'URL': pkg.URL,
'PackageBase': pkg.PackageBase.Name,
'NumVotes': pkg.PackageBase.NumVotes,
'Popularity': int(pkg.PackageBase.Popularity),
'OutOfDate': None,
'Maintainer': user.Username,
'URLPath': '/cgit/aur.git/snapshot/chungy-chungus.tar.gz',
'Depends': ['chungy-depends'],
'Conflicts': ['chungy-conflicts'],
'License': [],
'Keywords': []
}],
'resultcount': 1,
'type': 'multiinfo'
"version": 5,
"results": [
{
"Name": pkg.Name,
"Version": pkg.Version,
"Description": pkg.Description,
"URL": pkg.URL,
"PackageBase": pkg.PackageBase.Name,
"NumVotes": pkg.PackageBase.NumVotes,
"Popularity": int(pkg.PackageBase.Popularity),
"OutOfDate": None,
"Maintainer": user.Username,
"URLPath": "/cgit/aur.git/snapshot/chungy-chungus.tar.gz",
"Depends": ["chungy-depends"],
"Conflicts": ["chungy-conflicts"],
"License": [],
"Keywords": [],
}
],
"resultcount": 1,
"type": "multiinfo",
}
# Make dummy request.
with client as request:
response = request.get("/rpc", params={
"v": 5, "type": "info", "arg": "chungy-chungus"
})
response = request.get(
"/rpc", params={"v": 5, "type": "info", "arg": "chungy-chungus"}
)
response_data = orjson.loads(response.content.decode())
# Remove inconsistent keys.
@ -429,18 +497,18 @@ def test_rpc_no_dependencies_omits_key(client: TestClient, user: User,
def test_rpc_bad_type(client: TestClient):
# Define expected response.
expected_data = {
'version': 5,
'results': [],
'resultcount': 0,
'type': 'error',
'error': 'Incorrect request type specified.'
"version": 5,
"results": [],
"resultcount": 0,
"type": "error",
"error": "Incorrect request type specified.",
}
# Make dummy request.
with client as request:
response = request.get("/rpc", params={
"v": 5, "type": "invalid-type", "arg": "big-chungus"
})
response = request.get(
"/rpc", params={"v": 5, "type": "invalid-type", "arg": "big-chungus"}
)
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@ -452,18 +520,18 @@ def test_rpc_bad_type(client: TestClient):
def test_rpc_bad_version(client: TestClient):
# Define expected response.
expected_data = {
'version': 0,
'resultcount': 0,
'results': [],
'type': 'error',
'error': 'Invalid version specified.'
"version": 0,
"resultcount": 0,
"results": [],
"type": "error",
"error": "Invalid version specified.",
}
# Make dummy request.
with client as request:
response = request.get("/rpc", params={
"v": 0, "type": "info", "arg": "big-chungus"
})
response = request.get(
"/rpc", params={"v": 0, "type": "info", "arg": "big-chungus"}
)
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@ -475,19 +543,16 @@ def test_rpc_bad_version(client: TestClient):
def test_rpc_no_version(client: TestClient):
# Define expected response.
expected_data = {
'version': None,
'resultcount': 0,
'results': [],
'type': 'error',
'error': 'Please specify an API version.'
"version": None,
"resultcount": 0,
"results": [],
"type": "error",
"error": "Please specify an API version.",
}
# Make dummy request.
with client as request:
response = request.get("/rpc", params={
"type": "info",
"arg": "big-chungus"
})
response = request.get("/rpc", params={"type": "info", "arg": "big-chungus"})
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@ -499,11 +564,11 @@ def test_rpc_no_version(client: TestClient):
def test_rpc_no_type(client: TestClient):
# Define expected response.
expected_data = {
'version': 5,
'results': [],
'resultcount': 0,
'type': 'error',
'error': 'No request type/data specified.'
"version": 5,
"results": [],
"resultcount": 0,
"type": "error",
"error": "No request type/data specified.",
}
# Make dummy request.
@ -520,11 +585,11 @@ def test_rpc_no_type(client: TestClient):
def test_rpc_no_args(client: TestClient):
# Define expected response.
expected_data = {
'version': 5,
'results': [],
'resultcount': 0,
'type': 'error',
'error': 'No request type/data specified.'
"version": 5,
"results": [],
"resultcount": 0,
"type": "error",
"error": "No request type/data specified.",
}
# Make dummy request.
@ -541,9 +606,9 @@ def test_rpc_no_args(client: TestClient):
def test_rpc_no_maintainer(client: TestClient, packages: list[Package]):
# Make dummy request.
with client as request:
response = request.get("/rpc", params={
"v": 5, "type": "info", "arg": "woogly-chungus"
})
response = request.get(
"/rpc", params={"v": 5, "type": "info", "arg": "woogly-chungus"}
)
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@ -620,8 +685,12 @@ def mock_config_getint(section: str, key: str):
@mock.patch("aurweb.config.getint", side_effect=mock_config_getint)
def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient,
pipeline: Pipeline, packages: list[Package]):
def test_rpc_ratelimit(
getint: mock.MagicMock,
client: TestClient,
pipeline: Pipeline,
packages: list[Package],
):
params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"}
for i in range(4):
@ -685,7 +754,7 @@ def test_rpc_search(client: TestClient, packages: list[Package]):
headers = {"If-None-Match": etag}
response = request.get("/rpc", params=params, headers=headers)
assert response.status_code == int(HTTPStatus.NOT_MODIFIED)
assert response.content == b''
assert response.content == b""
# No args on non-m by types return an error.
del params["arg"]
@ -703,12 +772,7 @@ def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]):
# user1 maintains 4 packages; assert that we got them all.
assert data.get("resultcount") == 4
names = list(sorted(r.get("Name") for r in data.get("results")))
expected_results = [
"big-chungus",
"chungy-chungus",
"gluggly-chungus",
"other-pkg"
]
expected_results = ["big-chungus", "chungy-chungus", "gluggly-chungus", "other-pkg"]
assert names == expected_results
# Search for a non-existent maintainer, giving us zero packages.
@ -730,11 +794,10 @@ def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]):
assert result.get("Name") == "big-chungus"
def test_rpc_search_depends(client: TestClient, packages: list[Package],
depends: list[PackageDependency]):
params = {
"v": 5, "type": "search", "by": "depends", "arg": "chungus-depends"
}
def test_rpc_search_depends(
client: TestClient, packages: list[Package], depends: list[PackageDependency]
):
params = {"v": 5, "type": "search", "by": "depends", "arg": "chungus-depends"}
with client as request:
response = request.get("/rpc", params=params)
data = response.json()
@ -743,13 +806,14 @@ def test_rpc_search_depends(client: TestClient, packages: list[Package],
assert result.get("Name") == packages[0].Name
def test_rpc_search_makedepends(client: TestClient, packages: list[Package],
depends: list[PackageDependency]):
def test_rpc_search_makedepends(
client: TestClient, packages: list[Package], depends: list[PackageDependency]
):
params = {
"v": 5,
"type": "search",
"by": "makedepends",
"arg": "chungus-makedepends"
"arg": "chungus-makedepends",
}
with client as request:
response = request.get("/rpc", params=params)
@ -759,14 +823,10 @@ def test_rpc_search_makedepends(client: TestClient, packages: list[Package],
assert result.get("Name") == packages[0].Name
def test_rpc_search_optdepends(client: TestClient, packages: list[Package],
depends: list[PackageDependency]):
params = {
"v": 5,
"type": "search",
"by": "optdepends",
"arg": "chungus-optdepends"
}
def test_rpc_search_optdepends(
client: TestClient, packages: list[Package], depends: list[PackageDependency]
):
params = {"v": 5, "type": "search", "by": "optdepends", "arg": "chungus-optdepends"}
with client as request:
response = request.get("/rpc", params=params)
data = response.json()
@ -775,13 +835,14 @@ def test_rpc_search_optdepends(client: TestClient, packages: list[Package],
assert result.get("Name") == packages[0].Name
def test_rpc_search_checkdepends(client: TestClient, packages: list[Package],
depends: list[PackageDependency]):
def test_rpc_search_checkdepends(
client: TestClient, packages: list[Package], depends: list[PackageDependency]
):
params = {
"v": 5,
"type": "search",
"by": "checkdepends",
"arg": "chungus-checkdepends"
"arg": "chungus-checkdepends",
}
with client as request:
response = request.get("/rpc", params=params)
@ -799,21 +860,16 @@ def test_rpc_incorrect_by(client: TestClient):
def test_rpc_jsonp_callback(client: TestClient):
""" Test the callback parameter.
"""Test the callback parameter.
For end-to-end verification, the `examples/jsonp.html` file can be
used to submit jsonp callback requests to the RPC.
"""
params = {
"v": 5,
"type": "search",
"arg": "big",
"callback": "jsonCallback"
}
params = {"v": 5, "type": "search", "arg": "big", "callback": "jsonCallback"}
with client as request:
response = request.get("/rpc", params=params)
assert response.headers.get("content-type") == "text/javascript"
assert re.search(r'^/\*\*/jsonCallback\(.*\)$', response.text) is not None
assert re.search(r"^/\*\*/jsonCallback\(.*\)$", response.text) is not None
# Test an invalid callback name; we get an application/json error.
params["callback"] = "jsonCallback!"
@ -824,20 +880,14 @@ def test_rpc_jsonp_callback(client: TestClient):
def test_rpc_post(client: TestClient, packages: list[Package]):
data = {
"v": 5,
"type": "info",
"arg": "big-chungus",
"arg[]": ["chungy-chungus"]
}
data = {"v": 5, "type": "info", "arg": "big-chungus", "arg[]": ["chungy-chungus"]}
with client as request:
resp = request.post("/rpc", data=data)
assert resp.status_code == int(HTTPStatus.OK)
assert resp.json().get("resultcount") == 2
def test_rpc_too_many_search_results(client: TestClient,
packages: list[Package]):
def test_rpc_too_many_search_results(client: TestClient, packages: list[Package]):
config_getint = config.getint
def mock_config(section: str, key: str):
@ -858,10 +908,18 @@ def test_rpc_too_many_info_results(client: TestClient, packages: list[Package]):
# regardless of the number of related records.
with db.begin():
for i in range(len(packages) - 1):
db.create(PackageDependency, DepTypeID=DEPENDS_ID,
Package=packages[i], DepName=packages[i + 1].Name)
db.create(PackageRelation, RelTypeID=PROVIDES_ID,
Package=packages[i], RelName=packages[i + 1].Name)
db.create(
PackageDependency,
DepTypeID=DEPENDS_ID,
Package=packages[i],
DepName=packages[i + 1].Name,
)
db.create(
PackageRelation,
RelTypeID=PROVIDES_ID,
Package=packages[i],
RelName=packages[i + 1].Name,
)
config_getint = config.getint

View file

@ -2,7 +2,6 @@ from http import HTTPStatus
import lxml.etree
import pytest
from fastapi.testclient import TestClient
from aurweb import db, logging, time
@ -27,13 +26,15 @@ def client():
@pytest.fixture
def user():
account_type = db.query(AccountType,
AccountType.AccountType == "User").first()
yield db.create(User, Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountType=account_type)
account_type = db.query(AccountType, AccountType.AccountType == "User").first()
yield db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountType=account_type,
)
@pytest.fixture
@ -45,8 +46,12 @@ def packages(user):
with db.begin():
for i in range(101):
pkgbase = db.create(
PackageBase, Maintainer=user, Name=f"test-package-{i}",
SubmittedTS=(now + i), ModifiedTS=(now + i))
PackageBase,
Maintainer=user,
Name=f"test-package-{i}",
SubmittedTS=(now + i),
ModifiedTS=(now + i),
)
pkg = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
pkgs.append(pkg)
yield pkgs
@ -64,6 +69,7 @@ def test_rss(client, user, packages):
# Test that the RSS we got is sorted by descending SubmittedTS.
def key_(pkg):
return pkg.PackageBase.SubmittedTS
packages = list(reversed(sorted(packages, key=key_)))
# Just take the first 100.
@ -74,7 +80,7 @@ def test_rss(client, user, packages):
assert len(items) == 100
for i, item in enumerate(items):
title = next(iter(item.xpath('./title')))
title = next(iter(item.xpath("./title")))
logger.debug(f"title: '{title.text}' vs name: '{packages[i].Name}'")
assert title.text == packages[i].Name
@ -87,6 +93,7 @@ def test_rss_modified(client, user, packages):
# Test that the RSS we got is sorted by descending SubmittedTS.
def key_(pkg):
return pkg.PackageBase.ModifiedTS
packages = list(reversed(sorted(packages, key=key_)))
# Just take the first 100.
@ -97,6 +104,6 @@ def test_rss_modified(client, user, packages):
assert len(items) == 100
for i, item in enumerate(items):
title = next(iter(item.xpath('./title')))
title = next(iter(item.xpath("./title")))
logger.debug(f"title: '{title.text}' vs name: '{packages[i].Name}'")
assert title.text == packages[i].Name

View file

@ -2,7 +2,6 @@
from unittest import mock
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@ -19,17 +18,23 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
ResetKey="testReset", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
ResetKey="testReset",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def session(user: User) -> Session:
with db.begin():
session = db.create(Session, User=user, SessionID="testSession",
LastUpdateTS=time.utcnow())
session = db.create(
Session, User=user, SessionID="testSession", LastUpdateTS=time.utcnow()
)
yield session
@ -39,15 +44,21 @@ def test_session(user: User, session: Session):
def test_session_cs():
""" Test case sensitivity of the database table. """
"""Test case sensitivity of the database table."""
with db.begin():
user2 = db.create(User, Username="test2", Email="test2@example.org",
ResetKey="testReset2", Passwd="testPassword",
AccountTypeID=USER_ID)
user2 = db.create(
User,
Username="test2",
Email="test2@example.org",
ResetKey="testReset2",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
with db.begin():
session_cs = db.create(Session, User=user2, SessionID="TESTSESSION",
LastUpdateTS=time.utcnow())
session_cs = db.create(
Session, User=user2, SessionID="TESTSESSION", LastUpdateTS=time.utcnow()
)
assert session_cs.SessionID == "TESTSESSION"
assert session_cs.SessionID != "testSession"

View file

@ -1,6 +1,5 @@
import os
import tempfile
from typing import Tuple
from unittest import mock
@ -8,26 +7,21 @@ import pytest
import aurweb.config
import aurweb.spawn
from aurweb.exceptions import AurwebException
# Some os.environ overrides we use in this suite.
TEST_ENVIRONMENT = {
"PHP_NGINX_PORT": "8001",
"FASTAPI_NGINX_PORT": "8002"
}
TEST_ENVIRONMENT = {"PHP_NGINX_PORT": "8001", "FASTAPI_NGINX_PORT": "8002"}
class FakeProcess:
""" Fake a subprocess.Popen return object. """
"""Fake a subprocess.Popen return object."""
returncode = 0
stdout = b''
stderr = b''
stdout = b""
stderr = b""
def __init__(self, *args, **kwargs):
""" We need this constructor to remain compatible with Popen. """
pass
"""We need this constructor to remain compatible with Popen."""
def communicate(self) -> Tuple[bytes, bytes]:
return (self.stdout, self.stderr)
@ -40,10 +34,9 @@ class FakeProcess:
class MockFakeProcess:
""" FakeProcess construction helper to be used in mocks. """
"""FakeProcess construction helper to be used in mocks."""
def __init__(self, return_code: int = 0, stdout: bytes = b'',
stderr: bytes = b''):
def __init__(self, return_code: int = 0, stdout: bytes = b"", stderr: bytes = b""):
self.returncode = return_code
self.stdout = stdout
self.stderr = stderr
@ -101,7 +94,7 @@ def test_spawn_generate_nginx_config():
f'listen {php_host}:{TEST_ENVIRONMENT.get("PHP_NGINX_PORT")}',
f"proxy_pass http://{php_address}",
f'listen {fastapi_host}:{TEST_ENVIRONMENT.get("FASTAPI_NGINX_PORT")}',
f"proxy_pass http://{fastapi_address}"
f"proxy_pass http://{fastapi_address}",
]
for expected in expected_content:
assert expected in nginx_config

View file

@ -27,18 +27,23 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
@pytest.fixture
def pubkey(user: User) -> SSHPubKey:
with db.begin():
pubkey = db.create(SSHPubKey, User=user,
Fingerprint="testFingerprint",
PubKey="testPubKey")
pubkey = db.create(
SSHPubKey, User=user, Fingerprint="testFingerprint", PubKey="testPubKey"
)
yield pubkey
@ -50,11 +55,11 @@ def test_pubkey(user: User, pubkey: SSHPubKey):
def test_pubkey_cs(user: User):
""" Test case sensitivity of the database table. """
"""Test case sensitivity of the database table."""
with db.begin():
pubkey_cs = db.create(SSHPubKey, User=user,
Fingerprint="TESTFINGERPRINT",
PubKey="TESTPUBKEY")
pubkey_cs = db.create(
SSHPubKey, User=user, Fingerprint="TESTFINGERPRINT", PubKey="TESTPUBKEY"
)
assert pubkey_cs.Fingerprint == "TESTFINGERPRINT"
assert pubkey_cs.Fingerprint != "testFingerprint"

View file

@ -1,21 +1,23 @@
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
from aurweb.filters import timestamp_to_datetime as to_dt
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.templates import (
base_template,
make_context,
register_filter,
register_function,
)
from aurweb.testing.html import parse_root
from aurweb.testing.requests import Request
@ -35,19 +37,20 @@ def function():
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)
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)
def create_pkgrel(package: Package, reltype_id: int, relname: str) -> PackageRelation:
return db.create(
PackageRelation, Package=package, RelTypeID=reltype_id, RelName=relname
)
@pytest.fixture
@ -60,8 +63,13 @@ def user(db_test) -> User:
def pkgbase(user: User) -> PackageBase:
now = time.utcnow()
with db.begin():
pkgbase = db.create(PackageBase, Name="test-pkg", Maintainer=user,
SubmittedTS=now, ModifiedTS=now)
pkgbase = db.create(
PackageBase,
Name="test-pkg",
Maintainer=user,
SubmittedTS=now,
ModifiedTS=now,
)
yield pkgbase
@ -79,9 +87,10 @@ def create_license(pkg: Package, license_name: str) -> PackageLicense:
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. """
"""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
@ -93,8 +102,9 @@ def test_commit_hash():
commit_hash = "abcdefg"
long_commit_hash = commit_hash + "1234567"
def config_get_with_fallback(section: str, option: str,
fallback: str = None) -> str:
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)
@ -134,12 +144,12 @@ def pager_context(num_packages: int) -> dict[str, Any]:
"prefix": "/packages",
"total": num_packages,
"O": 0,
"PP": 50
"PP": 50,
}
def test_pager_no_results():
""" Test the pager partial with 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)
@ -151,7 +161,7 @@ def test_pager_no_results():
def test_pager():
""" Test the pager partial with two pages of results. """
"""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)
@ -274,17 +284,19 @@ def check_package_details(content: str, pkg: Package) -> None:
def test_package_details(user: User, package: Package):
""" Test package details with most fields populated, but not all. """
"""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,
"pkg": package,
"comaintainers": [],
})
context.update(
{
"request": request,
"git_clone_uri_anon": GIT_CLONE_URI_ANON,
"git_clone_uri_priv": GIT_CLONE_URI_PRIV,
"pkgbase": package.PackageBase,
"pkg": package,
"comaintainers": [],
}
)
base = base_template("partials/packages/details.html")
body = base.render(context, show_package_details=True)
@ -292,7 +304,7 @@ def test_package_details(user: User, package: Package):
def test_package_details_filled(user: User, package: Package):
""" Test package details with all fields populated. """
"""Test package details with all fields populated."""
pkgbase = package.PackageBase
with db.begin():
@ -311,19 +323,23 @@ def test_package_details_filled(user: User, package: Package):
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,
"pkg": package,
"comaintainers": [],
"licenses": package.package_licenses,
"provides": package.package_relations.filter(
PackageRelation.RelTypeID == PROVIDES_ID),
"replaces": package.package_relations.filter(
PackageRelation.RelTypeID == REPLACES_ID),
})
context.update(
{
"request": request,
"git_clone_uri_anon": GIT_CLONE_URI_ANON,
"git_clone_uri_priv": GIT_CLONE_URI_PRIV,
"pkgbase": package.PackageBase,
"pkg": 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)

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db
@ -13,8 +12,9 @@ def setup(db_test):
def test_term_creation():
with db.begin():
term = db.create(Term, Description="Term description",
URL="https://fake_url.io")
term = db.create(
Term, Description="Term description", URL="https://fake_url.io"
)
assert bool(term.ID)
assert term.Description == "Term description"
assert term.URL == "https://fake_url.io"

View file

@ -1,5 +1,4 @@
import aurweb.config
from aurweb.testing.requests import Request
from aurweb.time import get_request_timezone, tz_offset

View file

@ -1,12 +1,10 @@
import re
from http import HTTPStatus
from io import StringIO
from typing import Tuple
import lxml.etree
import pytest
from fastapi.testclient import TestClient
from aurweb import config, db, filters, time
@ -16,8 +14,8 @@ from aurweb.models.tu_voteinfo import TUVoteInfo
from aurweb.models.user import User
from aurweb.testing.requests import Request
DATETIME_REGEX = r'^[0-9]{4}-[0-9]{2}-[0-9]{2} \(.+\)$'
PARTICIPATION_REGEX = r'^1?[0-9]{2}[%]$' # 0% - 100%
DATETIME_REGEX = r"^[0-9]{4}-[0-9]{2}-[0-9]{2} \(.+\)$"
PARTICIPATION_REGEX = r"^1?[0-9]{2}[%]$" # 0% - 100%
def parse_root(html):
@ -43,11 +41,11 @@ def get_pkglist_directions(table):
def get_a(node):
return node.xpath('./a')[0].text.strip()
return node.xpath("./a")[0].text.strip()
def get_span(node):
return node.xpath('./span')[0].text.strip()
return node.xpath("./span")[0].text.strip()
def assert_current_vote_html(row, expected):
@ -82,39 +80,51 @@ def setup(db_test):
@pytest.fixture
def client():
from aurweb.asgi import app
yield TestClient(app=app)
@pytest.fixture
def tu_user():
tu_type = db.query(AccountType,
AccountType.AccountType == "Trusted User").first()
tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first()
with db.begin():
tu_user = db.create(User, Username="test_tu",
Email="test_tu@example.org",
RealName="Test TU", Passwd="testPassword",
AccountType=tu_type)
tu_user = db.create(
User,
Username="test_tu",
Email="test_tu@example.org",
RealName="Test TU",
Passwd="testPassword",
AccountType=tu_type,
)
yield tu_user
@pytest.fixture
def tu_user2():
with db.begin():
tu_user2 = db.create(User, Username="test_tu2",
Email="test_tu2@example.org",
RealName="Test TU 2", Passwd="testPassword",
AccountTypeID=TRUSTED_USER_ID)
tu_user2 = db.create(
User,
Username="test_tu2",
Email="test_tu2@example.org",
RealName="Test TU 2",
Passwd="testPassword",
AccountTypeID=TRUSTED_USER_ID,
)
yield tu_user2
@pytest.fixture
def user():
user_type = db.query(AccountType,
AccountType.AccountType == "User").first()
user_type = db.query(AccountType, AccountType.AccountType == "User").first()
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountType=user_type)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountType=user_type,
)
yield user
@ -126,10 +136,15 @@ def proposal(user, tu_user):
end = ts + 1000
with db.begin():
voteinfo = db.create(TUVoteInfo,
Agenda=agenda, Quorum=0.0,
User=user.Username, Submitter=tu_user,
Submitted=start, End=end)
voteinfo = db.create(
TUVoteInfo,
Agenda=agenda,
Quorum=0.0,
User=user.Username,
Submitter=tu_user,
Submitted=start,
End=end,
)
yield (tu_user, user, voteinfo)
@ -153,7 +168,7 @@ def test_tu_index_unauthorized(client: TestClient, user: User):
def test_tu_empty_index(client, tu_user):
""" Check an empty index when we don't create any records. """
"""Check an empty index when we don't create any records."""
# Make a default get request to /tu.
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
@ -179,18 +194,23 @@ def test_tu_index(client, tu_user):
# Create some test votes: (Agenda, Start, End).
votes = [
("Test agenda 1", ts - 5, ts + 1000), # Still running.
("Test agenda 2", ts - 1000, ts - 5) # Not running anymore.
("Test agenda 2", ts - 1000, ts - 5), # Not running anymore.
]
vote_records = []
with db.begin():
for vote in votes:
agenda, start, end = vote
vote_records.append(
db.create(TUVoteInfo, Agenda=agenda,
User=tu_user.Username,
Submitted=start, End=end,
Quorum=0.0,
Submitter=tu_user))
db.create(
TUVoteInfo,
Agenda=agenda,
User=tu_user.Username,
Submitted=start,
End=end,
Quorum=0.0,
Submitter=tu_user,
)
)
with db.begin():
# Vote on an ended proposal.
@ -202,21 +222,23 @@ def test_tu_index(client, tu_user):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
# Pass an invalid cby and pby; let them default to "desc".
response = request.get("/tu", cookies=cookies, params={
"cby": "BAD!",
"pby": "blah"
}, allow_redirects=False)
response = request.get(
"/tu",
cookies=cookies,
params={"cby": "BAD!", "pby": "blah"},
allow_redirects=False,
)
assert response.status_code == int(HTTPStatus.OK)
# Rows we expect to exist in HTML produced by /tu for current votes.
expected_rows = [
(
r'Test agenda 1',
r"Test agenda 1",
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
r'^(Yes|No)$'
r"^(Yes|No)$",
)
]
@ -239,13 +261,13 @@ def test_tu_index(client, tu_user):
# Rows we expect to exist in HTML produced by /tu for past votes.
expected_rows = [
(
r'Test agenda 2',
r"Test agenda 2",
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
r'^\d+$',
r'^\d+$',
r'^(Yes|No)$'
r"^\d+$",
r"^\d+$",
r"^(Yes|No)$",
)
]
@ -315,19 +337,27 @@ def test_tu_index_table_paging(client, tu_user):
with db.begin():
for i in range(25):
# Create 25 current votes.
db.create(TUVoteInfo, Agenda=f"Agenda #{i}",
User=tu_user.Username,
Submitted=(ts - 5), End=(ts + 1000),
Quorum=0.0,
Submitter=tu_user)
db.create(
TUVoteInfo,
Agenda=f"Agenda #{i}",
User=tu_user.Username,
Submitted=(ts - 5),
End=(ts + 1000),
Quorum=0.0,
Submitter=tu_user,
)
for i in range(25):
# Create 25 past votes.
db.create(TUVoteInfo, Agenda=f"Agenda #{25 + i}",
User=tu_user.Username,
Submitted=(ts - 1000), End=(ts - 5),
Quorum=0.0,
Submitter=tu_user)
db.create(
TUVoteInfo,
Agenda=f"Agenda #{25 + i}",
User=tu_user.Username,
Submitted=(ts - 1000),
End=(ts - 5),
Quorum=0.0,
Submitter=tu_user,
)
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
@ -347,7 +377,7 @@ def test_tu_index_table_paging(client, tu_user):
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
r'^(Yes|No)$'
r"^(Yes|No)$",
]
for i, row in enumerate(rows):
@ -361,9 +391,9 @@ def test_tu_index_table_paging(client, tu_user):
# Now, get the next page of current votes.
offset = 10 # Specify coff=10
with client as request:
response = request.get("/tu", cookies=cookies, params={
"coff": offset
}, allow_redirects=False)
response = request.get(
"/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.OK)
old_rows = rows
@ -390,9 +420,9 @@ def test_tu_index_table_paging(client, tu_user):
offset = 20 # Specify coff=10
with client as request:
response = request.get("/tu", cookies=cookies, params={
"coff": offset
}, allow_redirects=False)
response = request.get(
"/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.OK)
# Do it again, we only have five left.
@ -423,11 +453,15 @@ def test_tu_index_sorting(client, tu_user):
with db.begin():
for i in range(2):
# Create 'Agenda #1' and 'Agenda #2'.
db.create(TUVoteInfo, Agenda=f"Agenda #{i + 1}",
User=tu_user.Username,
Submitted=(ts + 5), End=(ts + 1000),
Quorum=0.0,
Submitter=tu_user)
db.create(
TUVoteInfo,
Agenda=f"Agenda #{i + 1}",
User=tu_user.Username,
Submitted=(ts + 5),
End=(ts + 1000),
Quorum=0.0,
Submitter=tu_user,
)
# Let's order each vote one day after the other.
# This will allow us to test the sorting nature
@ -446,27 +480,27 @@ def test_tu_index_sorting(client, tu_user):
rows = get_table_rows(table)
# The latest Agenda is at the top by default.
expected = [
"Agenda #2",
"Agenda #1"
]
expected = ["Agenda #2", "Agenda #1"]
assert len(rows) == len(expected)
for i, row in enumerate(rows):
assert_current_vote_html(row, [
expected[i],
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
r'^(Yes|No)$'
])
assert_current_vote_html(
row,
[
expected[i],
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
r"^(Yes|No)$",
],
)
# Make another request; one that sorts the current votes
# in ascending order instead of the default descending order.
with client as request:
response = request.get("/tu", cookies=cookies, params={
"cby": "asc"
}, allow_redirects=False)
response = request.get(
"/tu", cookies=cookies, params={"cby": "asc"}, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.OK)
# Get lxml handles of the document.
@ -478,30 +512,37 @@ def test_tu_index_sorting(client, tu_user):
rev_expected = list(reversed(expected))
assert len(rows) == len(rev_expected)
for i, row in enumerate(rows):
assert_current_vote_html(row, [
rev_expected[i],
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
r'^(Yes|No)$'
])
assert_current_vote_html(
row,
[
rev_expected[i],
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
r"^(Yes|No)$",
],
)
def test_tu_index_last_votes(client: TestClient, tu_user: User, tu_user2: User,
user: User):
def test_tu_index_last_votes(
client: TestClient, tu_user: User, tu_user2: User, user: User
):
ts = time.utcnow()
with db.begin():
# Create a proposal which has ended.
voteinfo = db.create(TUVoteInfo, Agenda="Test agenda",
User=user.Username,
Submitted=(ts - 1000),
End=(ts - 5),
Yes=1,
No=1,
ActiveTUs=1,
Quorum=0.0,
Submitter=tu_user)
voteinfo = db.create(
TUVoteInfo,
Agenda="Test agenda",
User=user.Username,
Submitted=(ts - 1000),
End=(ts - 5),
Yes=1,
No=1,
ActiveTUs=1,
Quorum=0.0,
Submitter=tu_user,
)
# Create a vote on it from tu_user.
db.create(TUVote, VoteInfo=voteinfo, User=tu_user)
@ -536,26 +577,27 @@ def test_tu_proposal_not_found(client, tu_user):
assert response.status_code == int(HTTPStatus.NOT_FOUND)
def test_tu_proposal_unauthorized(client: TestClient, user: User,
proposal: Tuple[User, User, TUVoteInfo]):
def test_tu_proposal_unauthorized(
client: TestClient, user: User, proposal: Tuple[User, User, TUVoteInfo]
):
cookies = {"AURSID": user.login(Request(), "testPassword")}
endpoint = f"/tu/{proposal[2].ID}"
with client as request:
response = request.get(endpoint, cookies=cookies,
allow_redirects=False)
response = request.get(endpoint, cookies=cookies, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
with client as request:
response = request.post(endpoint, cookies=cookies,
data={"decision": False},
allow_redirects=False)
response = request.post(
endpoint, cookies=cookies, data={"decision": False}, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
def test_tu_running_proposal(client: TestClient,
proposal: Tuple[User, User, TUVoteInfo]):
def test_tu_running_proposal(
client: TestClient, proposal: Tuple[User, User, TUVoteInfo]
):
tu_user, user, voteinfo = proposal
with db.begin():
voteinfo.ActiveTUs = 1
@ -576,8 +618,7 @@ def test_tu_running_proposal(client: TestClient,
assert vote_running.text.strip() == "This vote is still running."
# Verify User field.
username = details.xpath(
'./div[contains(@class, "user")]/strong/a/text()')[0]
username = details.xpath('./div[contains(@class, "user")]/strong/a/text()')[0]
assert username.strip() == user.Username
active = details.xpath('./div[contains(@class, "field")]')[1]
@ -585,10 +626,13 @@ def test_tu_running_proposal(client: TestClient,
assert "Active Trusted Users assigned:" in content
assert "1" in content
submitted = details.xpath(
'./div[contains(@class, "submitted")]/text()')[0]
assert re.match(r'^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$',
submitted.strip()) is not None
submitted = details.xpath('./div[contains(@class, "submitted")]/text()')[0]
assert (
re.match(
r"^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$", submitted.strip()
)
is not None
)
submitter = details.xpath('./div[contains(@class, "submitted")]/a')[0]
assert submitter.text.strip() == tu_user.Username
assert submitter.attrib["href"] == f"/account/{tu_user.Username}"
@ -598,8 +642,10 @@ def test_tu_running_proposal(client: TestClient,
assert end_label.strip() == "End:"
end_datetime = end.xpath("./strong/text()")[0]
assert re.match(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\)$',
end_datetime.strip()) is not None
assert (
re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\)$", end_datetime.strip())
is not None
)
# We have not voted yet. Assert that our voting form is shown.
form = root.xpath('//form[contains(@class, "action-form")]')[0]
@ -630,8 +676,7 @@ def test_tu_running_proposal(client: TestClient,
# Make another request now that we've voted.
with client as request:
response = request.get(
"/tu", params={"id": voteinfo.ID}, cookies=cookies)
response = request.get("/tu", params={"id": voteinfo.ID}, cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
# Parse our new root.
@ -685,12 +730,13 @@ def test_tu_ended_proposal(client, proposal):
def test_tu_proposal_vote_not_found(client, tu_user):
""" Test POST request to a missing vote. """
"""Test POST request to a missing vote."""
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
response = request.post("/tu/1", cookies=cookies,
data=data, allow_redirects=False)
response = request.post(
"/tu/1", cookies=cookies, data=data, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.NOT_FOUND)
@ -703,16 +749,14 @@ def test_tu_proposal_vote(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data)
response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data)
assert response.status_code == int(HTTPStatus.OK)
# Check that the proposal record got updated.
assert voteinfo.Yes == yes + 1
# Check that the new TUVote exists.
vote = db.query(TUVote, TUVote.VoteInfo == voteinfo,
TUVote.User == tu_user).first()
vote = db.query(TUVote, TUVote.VoteInfo == voteinfo, TUVote.User == tu_user).first()
assert vote is not None
root = parse_root(response.text)
@ -723,7 +767,8 @@ def test_tu_proposal_vote(client, proposal):
def test_tu_proposal_vote_unauthorized(
client: TestClient, proposal: Tuple[User, User, TUVoteInfo]):
client: TestClient, proposal: Tuple[User, User, TUVoteInfo]
):
tu_user, user, voteinfo = proposal
with db.begin():
@ -732,8 +777,9 @@ def test_tu_proposal_vote_unauthorized(
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data, allow_redirects=False)
response = request.post(
f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.UNAUTHORIZED)
root = parse_root(response.text)
@ -742,8 +788,9 @@ def test_tu_proposal_vote_unauthorized(
with client as request:
data = {"decision": "Yes"}
response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data, allow_redirects=False)
response = request.get(
f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@ -761,8 +808,9 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data, allow_redirects=False)
response = request.post(
f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
root = parse_root(response.text)
@ -771,8 +819,9 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal):
with client as request:
data = {"decision": "Yes"}
response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data, allow_redirects=False)
response = request.get(
f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@ -791,8 +840,9 @@ def test_tu_proposal_vote_already_voted(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data, allow_redirects=False)
response = request.post(
f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
root = parse_root(response.text)
@ -801,8 +851,9 @@ def test_tu_proposal_vote_already_voted(client, proposal):
with client as request:
data = {"decision": "Yes"}
response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data, allow_redirects=False)
response = request.get(
f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
)
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@ -816,8 +867,7 @@ def test_tu_proposal_vote_invalid_decision(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "EVIL"}
response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
data=data)
response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data)
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
assert response.text == "Invalid 'decision' value."
@ -829,18 +879,17 @@ def test_tu_addvote(client: TestClient, tu_user: User):
assert response.status_code == int(HTTPStatus.OK)
def test_tu_addvote_unauthorized(client: TestClient, user: User,
proposal: Tuple[User, User, TUVoteInfo]):
def test_tu_addvote_unauthorized(
client: TestClient, user: User, proposal: Tuple[User, User, TUVoteInfo]
):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
response = request.get("/addvote", cookies=cookies,
allow_redirects=False)
response = request.get("/addvote", cookies=cookies, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
with client as request:
response = request.post("/addvote", cookies=cookies,
allow_redirects=False)
response = request.post("/addvote", cookies=cookies, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
@ -848,8 +897,7 @@ def test_tu_addvote_unauthorized(client: TestClient, user: User,
def test_tu_addvote_invalid_type(client: TestClient, tu_user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
response = request.get("/addvote", params={"type": "faketype"},
cookies=cookies)
response = request.get("/addvote", params={"type": "faketype"}, cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@ -860,11 +908,7 @@ def test_tu_addvote_invalid_type(client: TestClient, tu_user: User):
def test_tu_addvote_post(client: TestClient, tu_user: User, user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
data = {
"user": user.Username,
"type": "add_tu",
"agenda": "Blah"
}
data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"}
with client as request:
response = request.post("/addvote", cookies=cookies, data=data)
@ -874,15 +918,12 @@ def test_tu_addvote_post(client: TestClient, tu_user: User, user: User):
assert voteinfo is not None
def test_tu_addvote_post_cant_duplicate_username(client: TestClient,
tu_user: User, user: User):
def test_tu_addvote_post_cant_duplicate_username(
client: TestClient, tu_user: User, user: User
):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
data = {
"user": user.Username,
"type": "add_tu",
"agenda": "Blah"
}
data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"}
with client as request:
response = request.post("/addvote", cookies=cookies, data=data)
@ -904,8 +945,7 @@ def test_tu_addvote_post_invalid_username(client: TestClient, tu_user: User):
assert response.status_code == int(HTTPStatus.NOT_FOUND)
def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User,
user: User):
def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User, user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
data = {"user": user.Username}
with client as request:
@ -913,8 +953,7 @@ def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User,
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
def test_tu_addvote_post_invalid_agenda(client: TestClient,
tu_user: User, user: User):
def test_tu_addvote_post_invalid_agenda(client: TestClient, tu_user: User, user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
data = {"user": user.Username, "type": "add_tu"}
with client as request:

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=TRUSTED_USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=TRUSTED_USER_ID,
)
yield user
@ -27,10 +31,15 @@ def user() -> User:
def tu_voteinfo(user: User) -> TUVoteInfo:
ts = time.utcnow()
with db.begin():
tu_voteinfo = db.create(TUVoteInfo, Agenda="Blah blah.",
User=user.Username,
Submitted=ts, End=ts + 5,
Quorum=0.5, Submitter=user)
tu_voteinfo = db.create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=ts,
End=ts + 5,
Quorum=0.5,
Submitter=user,
)
yield tu_voteinfo

View file

@ -1,5 +1,4 @@
import pytest
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@ -17,21 +16,29 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = create(User, Username="test", Email="test@example.org",
RealName="Test User", Passwd="testPassword",
AccountTypeID=TRUSTED_USER_ID)
user = create(
User,
Username="test",
Email="test@example.org",
RealName="Test User",
Passwd="testPassword",
AccountTypeID=TRUSTED_USER_ID,
)
yield user
def test_tu_voteinfo_creation(user: User):
ts = time.utcnow()
with db.begin():
tu_voteinfo = create(TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=ts, End=ts + 5,
Quorum=0.5,
Submitter=user)
tu_voteinfo = create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=ts,
End=ts + 5,
Quorum=0.5,
Submitter=user,
)
assert bool(tu_voteinfo.ID)
assert tu_voteinfo.Agenda == "Blah blah."
assert tu_voteinfo.User == user.Username
@ -50,12 +57,15 @@ def test_tu_voteinfo_creation(user: User):
def test_tu_voteinfo_is_running(user: User):
ts = time.utcnow()
with db.begin():
tu_voteinfo = create(TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=ts, End=ts + 1000,
Quorum=0.5,
Submitter=user)
tu_voteinfo = create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=ts,
End=ts + 1000,
Quorum=0.5,
Submitter=user,
)
assert tu_voteinfo.is_running() is True
with db.begin():
@ -66,12 +76,15 @@ def test_tu_voteinfo_is_running(user: User):
def test_tu_voteinfo_total_votes(user: User):
ts = time.utcnow()
with db.begin():
tu_voteinfo = create(TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=ts, End=ts + 1000,
Quorum=0.5,
Submitter=user)
tu_voteinfo = create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=ts,
End=ts + 1000,
Quorum=0.5,
Submitter=user,
)
tu_voteinfo.Yes = 1
tu_voteinfo.No = 3
@ -84,65 +97,81 @@ def test_tu_voteinfo_total_votes(user: User):
def test_tu_voteinfo_null_submitter_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
create(TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=0, End=0,
Quorum=0.50)
create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=0,
End=0,
Quorum=0.50,
)
rollback()
def test_tu_voteinfo_null_agenda_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
create(TUVoteInfo,
User=user.Username,
Submitted=0, End=0,
Quorum=0.50,
Submitter=user)
create(
TUVoteInfo,
User=user.Username,
Submitted=0,
End=0,
Quorum=0.50,
Submitter=user,
)
rollback()
def test_tu_voteinfo_null_user_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
create(TUVoteInfo,
Agenda="Blah blah.",
Submitted=0, End=0,
Quorum=0.50,
Submitter=user)
create(
TUVoteInfo,
Agenda="Blah blah.",
Submitted=0,
End=0,
Quorum=0.50,
Submitter=user,
)
rollback()
def test_tu_voteinfo_null_submitted_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
create(TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
End=0,
Quorum=0.50,
Submitter=user)
create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
End=0,
Quorum=0.50,
Submitter=user,
)
rollback()
def test_tu_voteinfo_null_end_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
create(TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=0,
Quorum=0.50,
Submitter=user)
create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=0,
Quorum=0.50,
Submitter=user,
)
rollback()
def test_tu_voteinfo_null_quorum_default(user: User):
with db.begin():
vi = create(TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=0, End=0,
Submitter=user)
vi = create(
TUVoteInfo,
Agenda="Blah blah.",
User=user.Username,
Submitted=0,
End=0,
Submitter=user,
)
assert vi.Quorum == 0

View file

@ -19,8 +19,13 @@ def create_vote(user: User, voteinfo: TUVoteInfo) -> TUVote:
def create_user(username: str, type_id: int):
with db.begin():
user = db.create(User, AccountTypeID=type_id, Username=username,
Email=f"{username}@example.org", Passwd=str())
user = db.create(
User,
AccountTypeID=type_id,
Username=username,
Email=f"{username}@example.org",
Passwd=str(),
)
return user
@ -32,9 +37,11 @@ def email_pieces(voteinfo: TUVoteInfo) -> Tuple[str, str]:
:return: tuple(subject, content)
"""
subject = f"TU Vote Reminder: Proposal {voteinfo.ID}"
content = (f"Please remember to cast your vote on proposal {voteinfo.ID} "
f"[1]. The voting period\nends in less than 48 hours.\n\n"
f"[1] {aur_location}/tu/?id={voteinfo.ID}")
content = (
f"Please remember to cast your vote on proposal {voteinfo.ID} "
f"[1]. The voting period\nends in less than 48 hours.\n\n"
f"[1] {aur_location}/tu/?id={voteinfo.ID}"
)
return (subject, content)
@ -58,14 +65,19 @@ def voteinfo(user: User) -> TUVoteInfo:
now = time.utcnow()
start = config.getint("tuvotereminder", "range_start")
with db.begin():
voteinfo = db.create(TUVoteInfo, Agenda="Lorem ipsum.",
User=user.Username, End=(now + start + 1),
Quorum=0.00, Submitter=user, Submitted=0)
voteinfo = db.create(
TUVoteInfo,
Agenda="Lorem ipsum.",
User=user.Username,
End=(now + start + 1),
Quorum=0.00,
Submitter=user,
Submitted=0,
)
yield voteinfo
def test_tu_vote_reminders(user: User, user2: User, user3: User,
voteinfo: TUVoteInfo):
def test_tu_vote_reminders(user: User, user2: User, user3: User, voteinfo: TUVoteInfo):
reminder.main()
assert Email.count() == 3
@ -75,7 +87,7 @@ def test_tu_vote_reminders(user: User, user2: User, user3: User,
# (to, content)
(user.Email, subject, content),
(user2.Email, subject, content),
(user3.Email, subject, content)
(user3.Email, subject, content),
]
for i, element in enumerate(expectations):
email, subject, content = element
@ -84,8 +96,9 @@ def test_tu_vote_reminders(user: User, user2: User, user3: User,
assert emails[i].body == content
def test_tu_vote_reminders_only_unvoted(user: User, user2: User, user3: User,
voteinfo: TUVoteInfo):
def test_tu_vote_reminders_only_unvoted(
user: User, user2: User, user3: User, voteinfo: TUVoteInfo
):
# Vote with user2 and user3; leaving only user to be notified.
create_vote(user2, voteinfo)
create_vote(user3, voteinfo)

View file

@ -1,6 +1,5 @@
import hashlib
import json
from datetime import datetime, timedelta
import bcrypt
@ -9,10 +8,14 @@ import pytest
import aurweb.auth
import aurweb.config
import aurweb.models.account_type as at
from aurweb import db
from aurweb.auth import creds
from aurweb.models.account_type import DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID
from aurweb.models.account_type import (
DEVELOPER_ID,
TRUSTED_USER_AND_DEV_ID,
TRUSTED_USER_ID,
USER_ID,
)
from aurweb.models.ban import Ban
from aurweb.models.package import Package
from aurweb.models.package_base import PackageBase
@ -31,10 +34,14 @@ def setup(db_test):
def create_user(username: str, account_type_id: int):
with db.begin():
user = db.create(User, Username=username,
Email=f"{username}@example.org",
RealName=username.title(), Passwd="testPassword",
AccountTypeID=account_type_id)
user = db.create(
User,
Username=username,
Email=f"{username}@example.org",
RealName=username.title(),
Passwd="testPassword",
AccountTypeID=account_type_id,
)
return user
@ -71,7 +78,7 @@ def package(user: User) -> Package:
def test_user_login_logout(user: User):
""" Test creating a user and reading its columns. """
"""Test creating a user and reading its columns."""
# Assert that make_user created a valid user.
assert bool(user.ID)
@ -89,8 +96,7 @@ def test_user_login_logout(user: User):
assert user.is_authenticated()
# Expect that User session relationships work right.
user_session = db.query(Session,
Session.UsersID == user.ID).first()
user_session = db.query(Session, Session.UsersID == user.ID).first()
assert user_session == user.session
assert user.session.SessionID == sid
assert user.session.User == user
@ -111,8 +117,10 @@ def test_user_login_logout(user: User):
assert result.is_authenticated()
# Test out user string functions.
assert repr(user) == f"<User(ID='{user.ID}', " + \
"AccountType='User', Username='test')>"
assert (
repr(user)
== f"<User(ID='{user.ID}', " + "AccountType='User', Username='test')>"
)
# Test logout.
user.logout(request)
@ -145,9 +153,7 @@ def test_user_login_suspended(user: User):
def test_legacy_user_authentication(user: User):
with db.begin():
user.Salt = bcrypt.gensalt().decode()
user.Passwd = hashlib.md5(
f"{user.Salt}testPassword".encode()
).hexdigest()
user.Passwd = hashlib.md5(f"{user.Salt}testPassword".encode()).hexdigest()
assert not user.valid_password("badPassword")
assert user.valid_password("testPassword")
@ -160,8 +166,12 @@ def test_user_login_with_outdated_sid(user: User):
# Make a session with a LastUpdateTS 5 seconds ago, causing
# user.login to update it with a new sid.
with db.begin():
db.create(Session, UsersID=user.ID, SessionID="stub",
LastUpdateTS=datetime.utcnow().timestamp() - 5)
db.create(
Session,
UsersID=user.ID,
SessionID="stub",
LastUpdateTS=datetime.utcnow().timestamp() - 5,
)
sid = user.login(Request(), "testPassword")
assert sid and user.is_authenticated()
assert sid != "stub"
@ -186,9 +196,12 @@ def test_user_ssh_pub_key(user: User):
assert user.ssh_pub_keys.first() is None
with db.begin():
ssh_pub_key = db.create(SSHPubKey, UserID=user.ID,
Fingerprint="testFingerprint",
PubKey="testPubKey")
ssh_pub_key = db.create(
SSHPubKey,
UserID=user.ID,
Fingerprint="testFingerprint",
PubKey="testPubKey",
)
assert user.ssh_pub_keys.first() == ssh_pub_key
@ -283,8 +296,9 @@ def test_user_packages(user: User, package: Package):
assert package in user.packages()
def test_can_edit_user(user: User, tu_user: User, dev_user: User,
tu_and_dev_user: User):
def test_can_edit_user(
user: User, tu_user: User, dev_user: User, tu_and_dev_user: User
):
# User can edit.
assert user.can_edit_user(user)

View file

@ -14,13 +14,18 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
user = db.create(User, Username="test", Email="test@example.org",
Passwd="testPassword", AccountTypeID=USER_ID)
user = db.create(
User,
Username="test",
Email="test@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID,
)
yield user
def test_usermaint_noop(user: User):
""" Last[SSH]Login isn't expired in this test: usermaint is noop. """
"""Last[SSH]Login isn't expired in this test: usermaint is noop."""
now = time.utcnow()
with db.begin():

View file

@ -1,10 +1,8 @@
import json
from http import HTTPStatus
import fastapi
import pytest
from fastapi.responses import JSONResponse
from aurweb import filters, util
@ -18,7 +16,7 @@ def test_round():
def test_git_search():
""" Test that git_search matches the full commit if necessary. """
"""Test that git_search matches the full commit if necessary."""
commit_hash = "0123456789abcdef"
repo = {commit_hash}
prefixlen = util.git_search(repo, commit_hash)
@ -26,7 +24,7 @@ def test_git_search():
def test_git_search_double_commit():
""" Test that git_search matches a shorter prefix length. """
"""Test that git_search matches a shorter prefix length."""
commit_hash = "0123456789abcdef"
repo = {commit_hash[:13]}
# Locate the shortest prefix length that matches commit_hash.
@ -36,7 +34,6 @@ def test_git_search_double_commit():
@pytest.mark.asyncio
async def test_error_or_result():
async def route(request: fastapi.Request):
raise RuntimeError("No response returned.")