pass no_report to handlers

This commit is contained in:
Evgenii Alekseev 2021-09-08 02:45:20 +03:00
parent a061ea96e6
commit 16587306dd
60 changed files with 232 additions and 134 deletions

View File

@ -77,7 +77,7 @@
{% if auth_username is none %}
<button type="button" class="btn btn-link" data-bs-toggle="modal" data-bs-target="#loginForm" style="text-decoration: none">login</button>
{% else %}
<form action="/logout" method="post">
<form action="/user-api/v1/logout" method="post">
<button type="submit" class="btn btn-link" style="text-decoration: none">logout ({{ auth_username }})</button>
</form>
{% endif %}
@ -88,19 +88,23 @@
<div id="loginForm" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-login">
<div class="modal-content">
<form action="/login" method="post">
<form action="/user-api/v1/login" method="post">
<div class="modal-header">
<h4 class="modal-title">login</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="username" class="col-form-label">username</label>
<input id="username" type="text" class="form-control" placeholder="enter username" name="username" required>
<div class="form-group row">
<label for="username" class="col-sm-2 col-form-label">username</label>
<div class="col-sm-10">
<input id="username" type="text" class="form-control" placeholder="enter username" name="username" required>
</div>
</div>
<div class="form-group">
<label for="password" class="col-form-label">password</label>
<input id="password" type="password" class="form-control" placeholder="enter username" name="password" required>
<div class="form-group row">
<label for="password" class="col-sm-2 col-form-label">password</label>
<div class="col-sm-10">
<input id="password" type="password" class="form-control" placeholder="enter password" name="password" required>
</div>
</div>
</div>
<div class="modal-footer">

View File

@ -76,7 +76,7 @@ def _parser() -> argparse.ArgumentParser:
_set_status_update_parser(subparsers)
_set_sync_parser(subparsers)
_set_update_parser(subparsers)
_set_web_parser(subparsers, parser)
_set_web_parser(subparsers)
return parser
@ -358,16 +358,15 @@ def _set_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
return parser
def _set_web_parser(root: SubParserAction, parent: argparse.ArgumentParser) -> argparse.ArgumentParser:
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for web subcommand
:param root: subparsers for the commands
:param parent: command line parser for the application
:return: created argument parser
"""
parser = root.add_parser("web", help="start web server", description="start web server",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.set_defaults(handler=handlers.Web, lock=None, no_report=True, parser=parent)
parser.set_defaults(handler=handlers.Web, lock=None, no_report=True, parser=_parser)
return parser

View File

@ -40,16 +40,17 @@ class Application:
:ivar repository: repository instance
"""
def __init__(self, architecture: str, configuration: Configuration) -> None:
def __init__(self, architecture: str, configuration: Configuration, no_report: bool) -> None:
"""
default constructor
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
self.logger = logging.getLogger("root")
self.configuration = configuration
self.architecture = architecture
self.repository = Repository(architecture, configuration)
self.repository = Repository(architecture, configuration, no_report)
def _finalize(self, built_packages: Iterable[Package]) -> None:
"""

View File

@ -32,14 +32,16 @@ class Add(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
application = Application(architecture, configuration)
application = Application(architecture, configuration, no_report)
application.add(args.package, args.without_dependencies)
if not args.now:
return

View File

@ -32,12 +32,14 @@ class Clean(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
Application(architecture, configuration).clean(args.no_build, args.no_cache, args.no_chroot,
args.no_manual, args.no_packages)
Application(architecture, configuration, no_report).clean(args.no_build, args.no_cache, args.no_chroot,
args.no_manual, args.no_packages)

View File

@ -34,12 +34,14 @@ class CreateUser(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
salt = CreateUser.get_salt(configuration)
user = CreateUser.create_user(args)

View File

@ -33,12 +33,14 @@ class Dump(Handler):
_print = print
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
dump = configuration.dump()
for section, values in sorted(dump.items()):

View File

@ -47,7 +47,7 @@ class Handler:
try:
configuration = Configuration.from_path(args.configuration, architecture, not args.no_log)
with Lock(args, architecture, configuration):
cls.run(args, architecture, configuration)
cls.run(args, architecture, configuration, args.no_report)
return True
except Exception:
logging.getLogger("root").exception("process exception")
@ -88,11 +88,13 @@ class Handler:
return architectures
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
raise NotImplementedError

View File

@ -32,11 +32,13 @@ class Init(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
Application(architecture, configuration).repository.repo.init()
Application(architecture, configuration, no_report).repository.repo.init()

View File

@ -32,11 +32,13 @@ class KeyImport(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
Application(architecture, configuration).repository.sign.import_key(args.key_server, args.key)
Application(architecture, configuration, no_report).repository.sign.import_key(args.key_server, args.key)

View File

@ -32,16 +32,18 @@ class Rebuild(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
depends_on = set(args.depends_on) if args.depends_on else None
application = Application(architecture, configuration)
application = Application(architecture, configuration, no_report)
packages = [
package
for package in application.repository.packages()

View File

@ -32,11 +32,13 @@ class Remove(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
Application(architecture, configuration).remove(args.package)
Application(architecture, configuration, no_report).remove(args.package)

View File

@ -33,14 +33,16 @@ class RemoveUnknown(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
application = Application(architecture, configuration)
application = Application(architecture, configuration, no_report)
unknown_packages = application.unknown()
if args.dry_run:
for package in unknown_packages:

View File

@ -32,11 +32,13 @@ class Report(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
Application(architecture, configuration).report(args.target, [])
Application(architecture, configuration, no_report).report(args.target, [])

View File

@ -32,12 +32,14 @@ class Search(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
search = " ".join(args.search)
packages = aur.search(search)

View File

@ -43,14 +43,16 @@ class Setup(Handler):
SUDOERS_PATH = Path("/etc/sudoers.d/ahriman")
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
application = Application(architecture, configuration)
application = Application(architecture, configuration, no_report)
Setup.create_makepkg_configuration(args.packager, application.repository.paths)
Setup.create_executable(args.build_command, architecture)
Setup.create_devtools_configuration(args.build_command, architecture, args.from_configuration,

View File

@ -32,11 +32,13 @@ class Sign(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
Application(architecture, configuration).sign(args.package)
Application(architecture, configuration, no_report).sign(args.package)

View File

@ -34,24 +34,27 @@ class Status(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
application = Application(architecture, configuration)
# we are using reporter here
client = Application(architecture, configuration, no_report=False).repository.reporter
if args.ahriman:
ahriman = application.repository.reporter.get_self()
ahriman = client.get_self()
print(ahriman.pretty_print())
print()
if args.package:
packages: Iterable[Tuple[Package, BuildStatus]] = sum(
[application.repository.reporter.get(base) for base in args.package],
[client.get(base) for base in args.package],
start=[])
else:
packages = application.repository.reporter.get(None)
packages = client.get(None)
for package, package_status in sorted(packages, key=lambda item: item[0].base):
print(package.pretty_print())
print(f"\t{package.version}")

View File

@ -32,14 +32,17 @@ class StatusUpdate(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
client = Application(architecture, configuration).repository.reporter
# we are using reporter here
client = Application(architecture, configuration, no_report=False).repository.reporter
callback: Callable[[str], None] = lambda p: client.remove(p) if args.remove else client.update(p, args.status)
if args.package:
# update packages statuses

View File

@ -32,11 +32,13 @@ class Sync(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
Application(architecture, configuration).sync(args.target, [])
Application(architecture, configuration, no_report).sync(args.target, [])

View File

@ -32,14 +32,16 @@ class Update(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
application = Application(architecture, configuration)
application = Application(architecture, configuration, no_report)
packages = application.get_updates(args.package, args.no_aur, args.no_manual, args.no_vcs,
Update.log_fn(application, args.dry_run))
if args.dry_run:

View File

@ -32,17 +32,19 @@ class Web(Handler):
"""
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
configuration: Configuration, no_report: bool) -> None:
"""
callback for command line
:param args: command line args
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
# we are using local import for optional dependencies
from ahriman.web.web import run_server, setup_service
spawner = Spawn(args.parser, architecture, configuration)
spawner = Spawn(args.parser(), architecture, configuration)
spawner.start()
application = setup_service(architecture, configuration, spawner)

View File

@ -19,7 +19,7 @@
#
from __future__ import annotations
from typing import Optional, Set, Type
from typing import Optional, Type
from ahriman.core.configuration import Configuration
from ahriman.models.auth_settings import AuthSettings
@ -36,8 +36,8 @@ class Auth:
:cvar ALLOWED_PATHS_GROUPS: URI paths prefixes which can be accessed without authorization, predefined
"""
ALLOWED_PATHS = {"/", "/favicon.ico", "/index.html", "/login", "/logout"}
ALLOWED_PATHS_GROUPS: Set[str] = set()
ALLOWED_PATHS = {"/", "/favicon.ico", "/index.html"}
ALLOWED_PATHS_GROUPS = {"/user-api"}
def __init__(self, configuration: Configuration, provider: AuthSettings = AuthSettings.Disabled) -> None:
"""

View File

@ -43,7 +43,13 @@ class Properties:
:ivar sign: GPG wrapper instance
"""
def __init__(self, architecture: str, configuration: Configuration) -> None:
def __init__(self, architecture: str, configuration: Configuration, no_report: bool) -> None:
"""
default constructor
:param architecture: repository architecture
:param configuration: configuration instance
:param no_report: force disable reporting
"""
self.logger = logging.getLogger("builder")
self.architecture = architecture
self.configuration = configuration
@ -58,4 +64,4 @@ class Properties:
self.pacman = Pacman(configuration)
self.sign = GPG(architecture, configuration)
self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
self.reporter = Client.load(configuration)
self.reporter = Client() if no_report else Client.load(configuration)

View File

@ -49,7 +49,7 @@ class Watcher:
self.logger = logging.getLogger("http")
self.architecture = architecture
self.repository = Repository(architecture, configuration)
self.repository = Repository(architecture, configuration, no_report=True)
self.known: Dict[str, Tuple[Package, BuildStatus]] = {}
self.status = BuildStatus()

View File

@ -65,7 +65,7 @@ class WebClient(Client):
"""
:return: full url for web service to login
"""
return f"{self.address}/login"
return f"{self.address}/user-api/v1/login"
@property
def _status_url(self) -> str:

View File

@ -51,7 +51,7 @@ class User:
"""
if username is None or password is None:
return None
return cls(username, password, UserAccess.Status)
return cls(username, password, UserAccess.Read)
@staticmethod
def generate_password(length: int) -> str:

View File

@ -25,9 +25,7 @@ class UserAccess(Enum):
web user access enumeration
:cvar Read: user can read status page
:cvar Write: user can modify task and package list
:cvar Status: user can update statuses via API
"""
Read = "read"
Write = "write"
Status = "status"

View File

@ -73,9 +73,7 @@ def auth_handler(validator: Auth) -> MiddlewareType:
"""
@middleware
async def handle(request: Request, handler: HandlerType) -> StreamResponse:
if request.path.startswith("/status-api"):
permission = UserAccess.Status
elif request.method in ("GET", "HEAD", "OPTIONS"):
if request.method in ("GET", "HEAD", "OPTIONS"):
permission = UserAccess.Read
else:
permission = UserAccess.Write

View File

@ -37,8 +37,8 @@ def setup_routes(application: Application) -> None:
GET / get build status page
GET /index.html same as above
POST /login login to service
POST /logout logout from service
POST /user-api/v1/login login to service
POST /user-api/v1/logout logout from service
GET /status-api/v1/ahriman get current service status
POST /status-api/v1/ahriman update service status
@ -57,8 +57,8 @@ def setup_routes(application: Application) -> None:
application.router.add_get("/", IndexView, allow_head=True)
application.router.add_get("/index.html", IndexView, allow_head=True)
application.router.add_post("/login", LoginView)
application.router.add_post("/logout", LogoutView)
application.router.add_post("/user-api/v1/login", LoginView)
application.router.add_post("/user-api/v1/logout", LogoutView)
application.router.add_get("/status-api/v1/ahriman", AhrimanView, allow_head=True)
application.router.add_post("/status-api/v1/ahriman", AhrimanView)

View File

@ -20,7 +20,7 @@ def application(configuration: Configuration, mocker: MockerFixture) -> Applicat
:return: application test instance
"""
mocker.patch("pathlib.Path.mkdir")
return Application("x86_64", configuration)
return Application("x86_64", configuration, no_report=True)
@pytest.fixture

View File

@ -94,4 +94,4 @@ def test_run(args: argparse.Namespace, configuration: Configuration) -> None:
must raise NotImplemented for missing method
"""
with pytest.raises(NotImplementedError):
Handler.run(args, "x86_64", configuration)
Handler.run(args, "x86_64", configuration, True)

View File

@ -26,7 +26,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.application.application.Application.add")
Add.run(args, "x86_64", configuration)
Add.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()
@ -41,6 +41,6 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
application_mock = mocker.patch("ahriman.application.application.Application.update")
updates_mock = mocker.patch("ahriman.application.application.Application.get_updates")
Add.run(args, "x86_64", configuration)
Add.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()
updates_mock.assert_called_once()

View File

@ -28,5 +28,5 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.application.application.Application.clean")
Clean.run(args, "x86_64", configuration)
Clean.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()

View File

@ -19,7 +19,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
"""
args.username = "user"
args.password = "pa55w0rd"
args.role = UserAccess.Status
args.role = UserAccess.Read
args.as_service = False
return args
@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
create_user = mocker.patch("ahriman.application.handlers.CreateUser.create_user")
get_salt_mock = mocker.patch("ahriman.application.handlers.CreateUser.get_salt")
CreateUser.run(args, "x86_64", configuration)
CreateUser.run(args, "x86_64", configuration, True)
get_auth_configuration_mock.assert_called_once()
create_configuration_mock.assert_called_once()
create_user.assert_called_once()

View File

@ -15,6 +15,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump",
return_value=configuration.dump())
Dump.run(args, "x86_64", configuration)
Dump.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()
print_mock.assert_called()

View File

@ -13,6 +13,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
create_tree_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.create_tree")
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
Init.run(args, "x86_64", configuration)
Init.run(args, "x86_64", configuration, True)
create_tree_mock.assert_called_once()
init_mock.assert_called_once()

View File

@ -25,5 +25,5 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.core.sign.gpg.GPG.import_key")
KeyImport.run(args, "x86_64", configuration)
KeyImport.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()

View File

@ -26,7 +26,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages")
application_mock = mocker.patch("ahriman.application.application.Application.update")
Rebuild.run(args, "x86_64", configuration)
Rebuild.run(args, "x86_64", configuration, True)
application_packages_mock.assert_called_once()
application_mock.assert_called_once()
@ -44,7 +44,7 @@ def test_run_filter(args: argparse.Namespace, configuration: Configuration,
return_value=[package_ahriman, package_python_schedule])
application_mock = mocker.patch("ahriman.application.application.Application.update")
Rebuild.run(args, "x86_64", configuration)
Rebuild.run(args, "x86_64", configuration, True)
application_mock.assert_called_with([package_ahriman])
@ -60,5 +60,5 @@ def test_run_without_filter(args: argparse.Namespace, configuration: Configurati
return_value=[package_ahriman, package_python_schedule])
application_mock = mocker.patch("ahriman.application.application.Application.update")
Rebuild.run(args, "x86_64", configuration)
Rebuild.run(args, "x86_64", configuration, True)
application_mock.assert_called_with([package_ahriman, package_python_schedule])

View File

@ -24,5 +24,5 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.application.application.Application.remove")
Remove.run(args, "x86_64", configuration)
Remove.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()

View File

@ -26,7 +26,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.application.application.Application.unknown")
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
RemoveUnknown.run(args, "x86_64", configuration)
RemoveUnknown.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()
remove_mock.assert_called_once()
@ -44,7 +44,7 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, pac
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
log_fn_mock = mocker.patch("ahriman.application.handlers.remove_unknown.RemoveUnknown.log_fn")
RemoveUnknown.run(args, "x86_64", configuration)
RemoveUnknown.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()
remove_mock.assert_not_called()
log_fn_mock.assert_called_with(package_ahriman)

View File

@ -24,5 +24,5 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.application.application.Application.report")
Report.run(args, "x86_64", configuration)
Report.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()

View File

@ -26,7 +26,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, aur_package
mocker.patch("aur.search", return_value=[aur_package_ahriman])
log_mock = mocker.patch("ahriman.application.handlers.search.Search.log_fn")
Search.run(args, "x86_64", configuration)
Search.run(args, "x86_64", configuration, True)
log_mock.assert_called_once()
@ -38,7 +38,7 @@ def test_run_multiple_search(args: argparse.Namespace, configuration: Configurat
args.search = ["ahriman", "is", "cool"]
search_mock = mocker.patch("aur.search")
Search.run(args, "x86_64", configuration)
Search.run(args, "x86_64", configuration, True)
search_mock.assert_called_with(" ".join(args.search))
@ -51,5 +51,5 @@ def test_log_fn(args: argparse.Namespace, configuration: Configuration, aur_pack
mocker.patch("aur.search", return_value=[aur_package_ahriman])
print_mock = mocker.patch("builtins.print")
Search.run(args, "x86_64", configuration)
Search.run(args, "x86_64", configuration, True)
print_mock.assert_called() # we don't really care about call details tbh

View File

@ -39,7 +39,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
sudo_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.create_sudo_configuration")
executable_mock = mocker.patch("ahriman.application.handlers.setup.Setup.create_executable")
Setup.run(args, "x86_64", configuration)
Setup.run(args, "x86_64", configuration, True)
ahriman_configuration_mock.assert_called_once()
devtools_configuration_mock.assert_called_once()
makepkg_configuration_mock.assert_called_once()

View File

@ -24,5 +24,5 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.application.application.Application.sign")
Sign.run(args, "x86_64", configuration)
Sign.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()

View File

@ -30,7 +30,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, package_ahr
packages_mock = mocker.patch("ahriman.core.status.client.Client.get",
return_value=[(package_ahriman, BuildStatus())])
Status.run(args, "x86_64", configuration)
Status.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()
packages_mock.assert_called_once()
@ -46,5 +46,17 @@ def test_run_with_package_filter(args: argparse.Namespace, configuration: Config
packages_mock = mocker.patch("ahriman.core.status.client.Client.get",
return_value=[(package_ahriman, BuildStatus())])
Status.run(args, "x86_64", configuration)
Status.run(args, "x86_64", configuration, True)
packages_mock.assert_called_once()
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must create application object with native reporting
"""
args = _default_args(args)
mocker.patch("pathlib.Path.mkdir")
load_mock = mocker.patch("ahriman.core.status.client.Client.load")
Status.run(args, "x86_64", configuration, True)
load_mock.assert_called_once()

View File

@ -28,7 +28,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
update_self_mock = mocker.patch("ahriman.core.status.client.Client.update_self")
StatusUpdate.run(args, "x86_64", configuration)
StatusUpdate.run(args, "x86_64", configuration, True)
update_self_mock.assert_called_once()
@ -42,7 +42,7 @@ def test_run_packages(args: argparse.Namespace, configuration: Configuration, pa
mocker.patch("pathlib.Path.mkdir")
update_mock = mocker.patch("ahriman.core.status.client.Client.update")
StatusUpdate.run(args, "x86_64", configuration)
StatusUpdate.run(args, "x86_64", configuration, True)
update_mock.assert_called_once()
@ -57,5 +57,17 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, pack
mocker.patch("pathlib.Path.mkdir")
update_mock = mocker.patch("ahriman.core.status.client.Client.remove")
StatusUpdate.run(args, "x86_64", configuration)
StatusUpdate.run(args, "x86_64", configuration, True)
update_mock.assert_called_once()
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must create application object with native reporting
"""
args = _default_args(args)
mocker.patch("pathlib.Path.mkdir")
load_mock = mocker.patch("ahriman.core.status.client.Client.load")
StatusUpdate.run(args, "x86_64", configuration, True)
load_mock.assert_called_once()

View File

@ -24,5 +24,5 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.application.application.Application.sync")
Sync.run(args, "x86_64", configuration)
Sync.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()

View File

@ -30,7 +30,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.application.application.Application.update")
updates_mock = mocker.patch("ahriman.application.application.Application.get_updates")
Update.run(args, "x86_64", configuration)
Update.run(args, "x86_64", configuration, True)
application_mock.assert_called_once()
updates_mock.assert_called_once()
@ -44,7 +44,7 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, moc
mocker.patch("pathlib.Path.mkdir")
updates_mock = mocker.patch("ahriman.application.application.Application.get_updates")
Update.run(args, "x86_64", configuration)
Update.run(args, "x86_64", configuration, True)
updates_mock.assert_called_once()

View File

@ -12,7 +12,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
:param args: command line arguments fixture
:return: generated arguments for these test cases
"""
args.parser = True
args.parser = lambda: True
return args
@ -26,6 +26,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
setup_mock = mocker.patch("ahriman.web.web.setup_service")
run_mock = mocker.patch("ahriman.web.web.run_server")
Web.run(args, "x86_64", configuration)
Web.run(args, "x86_64", configuration, True)
setup_mock.assert_called_once()
run_mock.assert_called_once()

View File

@ -265,7 +265,7 @@ def test_subparsers_web(parser: argparse.ArgumentParser) -> None:
args = parser.parse_args(["-a", "x86_64", "web"])
assert args.lock is None
assert args.no_report
assert args.parser == parser
assert args.parser is not None and args.parser()
def test_run(args: argparse.Namespace, mocker: MockerFixture) -> None:

View File

@ -188,7 +188,7 @@ def user() -> User:
fixture for user descriptor
:return: user descriptor instance
"""
return User("user", "pa55w0rd", UserAccess.Status)
return User("user", "pa55w0rd", UserAccess.Read)
@pytest.fixture

View File

@ -46,8 +46,8 @@ def test_is_safe_request(auth: Auth) -> None:
must validate safe request
"""
# login and logout are always safe
assert auth.is_safe_request("/login", UserAccess.Write)
assert auth.is_safe_request("/logout", UserAccess.Write)
assert auth.is_safe_request("/user-api/v1/login", UserAccess.Write)
assert auth.is_safe_request("/user-api/v1/logout", UserAccess.Write)
auth.allowed_paths.add("/safe")
auth.allowed_paths_groups.add("/unsafe/safe")

View File

@ -19,7 +19,7 @@ def cleaner(configuration: Configuration, mocker: MockerFixture) -> Cleaner:
:return: cleaner test instance
"""
mocker.patch("pathlib.Path.mkdir")
return Cleaner("x86_64", configuration)
return Cleaner("x86_64", configuration, no_report=True)
@pytest.fixture
@ -36,7 +36,7 @@ def executor(configuration: Configuration, mocker: MockerFixture) -> Executor:
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_chroot")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_manual")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_packages")
return Executor("x86_64", configuration)
return Executor("x86_64", configuration, no_report=True)
@pytest.fixture
@ -48,7 +48,7 @@ def repository(configuration: Configuration, mocker: MockerFixture) -> Repositor
:return: repository test instance
"""
mocker.patch("pathlib.Path.mkdir")
return Repository("x86_64", configuration)
return Repository("x86_64", configuration, no_report=True)
@pytest.fixture
@ -58,7 +58,7 @@ def properties(configuration: Configuration) -> Properties:
:param configuration: configuration fixture
:return: properties test instance
"""
return Properties("x86_64", configuration)
return Properties("x86_64", configuration, no_report=True)
@pytest.fixture
@ -75,4 +75,4 @@ def update_handler(configuration: Configuration, mocker: MockerFixture) -> Updat
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_chroot")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_manual")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_packages")
return UpdateHandler("x86_64", configuration)
return UpdateHandler("x86_64", configuration, no_report=True)

View File

@ -2,6 +2,7 @@ from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.repository.properties import Properties
from ahriman.core.status.web_client import WebClient
def test_create_tree_on_load(configuration: Configuration, mocker: MockerFixture) -> None:
@ -9,6 +10,29 @@ def test_create_tree_on_load(configuration: Configuration, mocker: MockerFixture
must create tree on load
"""
create_tree_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.create_tree")
Properties("x86_64", configuration)
Properties("x86_64", configuration, True)
create_tree_mock.assert_called_once()
def test_create_dummy_report_client(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must create dummy report client if report is disabled
"""
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.create_tree")
load_mock = mocker.patch("ahriman.core.status.client.Client.load")
properties = Properties("x86_64", configuration, True)
load_mock.assert_not_called()
assert not isinstance(properties.reporter, WebClient)
def test_create_full_report_client(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must create load report client if report is enabled
"""
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.create_tree")
load_mock = mocker.patch("ahriman.core.status.client.Client.load")
Properties("x86_64", configuration, False)
load_mock.assert_called_once()

View File

@ -5,12 +5,28 @@ from pathlib import Path
from pytest_mock import MockerFixture
from unittest.mock import PropertyMock
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import UnknownPackage
from ahriman.core.status.watcher import Watcher
from ahriman.core.status.web_client import WebClient
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.package import Package
def test_force_no_report(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must force dummy report client
"""
configuration.set_option("web", "port", "8080")
mocker.patch("pathlib.Path.mkdir")
load_mock = mocker.patch("ahriman.core.status.client.Client.load")
watcher = Watcher("x86_64", configuration)
load_mock.assert_not_called()
assert not isinstance(watcher.repository.reporter, WebClient)
def test_cache_load(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must load state from cache

View File

@ -7,7 +7,7 @@ def test_from_option(user: User) -> None:
must generate user from options
"""
assert User.from_option(user.username, user.password) == user
# default is status access
# default is read access
user.access = UserAccess.Write
assert User.from_option(user.username, user.password) != user
@ -52,17 +52,6 @@ def test_verify_access_read(user: User) -> None:
user.access = UserAccess.Read
assert user.verify_access(UserAccess.Read)
assert not user.verify_access(UserAccess.Write)
assert not user.verify_access(UserAccess.Status)
def test_verify_access_status(user: User) -> None:
"""
user with status access must be able to only request status
"""
user.access = UserAccess.Status
assert not user.verify_access(UserAccess.Read)
assert not user.verify_access(UserAccess.Write)
assert user.verify_access(UserAccess.Status)
def test_verify_access_write(user: User) -> None:
@ -72,4 +61,3 @@ def test_verify_access_write(user: User) -> None:
user.access = UserAccess.Write
assert user.verify_access(UserAccess.Read)
assert user.verify_access(UserAccess.Write)
assert user.verify_access(UserAccess.Status)

View File

@ -41,7 +41,7 @@ async def test_auth_handler_api(auth: Auth, mocker: MockerFixture) -> None:
handler = auth_handler(auth)
await handler(aiohttp_request, request_handler)
check_permission_mock.assert_called_with(aiohttp_request, UserAccess.Status, aiohttp_request.path)
check_permission_mock.assert_called_with(aiohttp_request, UserAccess.Read, aiohttp_request.path)
async def test_auth_handler_api_post(auth: Auth, mocker: MockerFixture) -> None:
@ -55,7 +55,7 @@ async def test_auth_handler_api_post(auth: Auth, mocker: MockerFixture) -> None:
handler = auth_handler(auth)
await handler(aiohttp_request, request_handler)
check_permission_mock.assert_called_with(aiohttp_request, UserAccess.Status, aiohttp_request.path)
check_permission_mock.assert_called_with(aiohttp_request, UserAccess.Write, aiohttp_request.path)
async def test_auth_handler_read(auth: Auth, mocker: MockerFixture) -> None:

View File

@ -11,10 +11,10 @@ async def test_post(client_with_auth: TestClient, user: User, mocker: MockerFixt
payload = {"username": user.username, "password": user.password}
remember_mock = mocker.patch("aiohttp_security.remember")
post_response = await client_with_auth.post("/login", json=payload)
post_response = await client_with_auth.post("/user-api/v1/login", json=payload)
assert post_response.status == 200
post_response = await client_with_auth.post("/login", data=payload)
post_response = await client_with_auth.post("/user-api/v1/login", data=payload)
assert post_response.status == 200
remember_mock.assert_called()
@ -25,7 +25,7 @@ async def test_post_skip(client: TestClient, user: User) -> None:
must process if no auth configured
"""
payload = {"username": user.username, "password": user.password}
post_response = await client.post("/login", json=payload)
post_response = await client.post("/user-api/v1/login", json=payload)
assert post_response.status == 200
@ -36,6 +36,6 @@ async def test_post_unauthorized(client_with_auth: TestClient, user: User, mocke
payload = {"username": user.username, "password": ""}
remember_mock = mocker.patch("aiohttp_security.remember")
post_response = await client_with_auth.post("/login", json=payload)
post_response = await client_with_auth.post("/user-api/v1/login", json=payload)
assert post_response.status == 401
remember_mock.assert_not_called()

View File

@ -10,7 +10,7 @@ async def test_post(client_with_auth: TestClient, mocker: MockerFixture) -> None
mocker.patch("aiohttp_security.check_authorized")
forget_mock = mocker.patch("aiohttp_security.forget")
post_response = await client_with_auth.post("/logout")
post_response = await client_with_auth.post("/user-api/v1/logout")
assert post_response.status == 200
forget_mock.assert_called_once()
@ -22,7 +22,7 @@ async def test_post_unauthorized(client_with_auth: TestClient, mocker: MockerFix
mocker.patch("aiohttp_security.check_authorized", side_effect=HTTPUnauthorized())
forget_mock = mocker.patch("aiohttp_security.forget")
post_response = await client_with_auth.post("/logout")
post_response = await client_with_auth.post("/user-api/v1/logout")
assert post_response.status == 401
forget_mock.assert_not_called()
@ -31,5 +31,5 @@ async def test_post_disabled(client: TestClient) -> None:
"""
must raise exception if auth is disabled
"""
post_response = await client.post("/logout")
post_response = await client.post("/user-api/v1/logout")
assert post_response.status == 200