mirror of
https://github.com/ipnet-mesh/meshcore-hub.git
synced 2026-11-03 20:12:22 +01:00
- api CLI single-process path now passes spam_detection_enabled / spam_score_threshold to create_app() so the messages hide-filter actually runs in the default (Docker) deployment - OIDC role names (oidc_role_admin/operator/member/test) moved from WebSettings to CommonSettings and wired onto API app.state; the API tier previously matched hardcoded role names, ignoring customized OIDC_ROLE_* config in authz, channel visibility, and tag/adoption checks (oidc_roles_claim stays web-only) - /metrics handler is now sync def so collection runs in the threadpool instead of blocking the event loop; hoisted fragile in-loop imports - evaluate_route_history gates max_path_length on the packet's true hop count (RawPacket.path_len) instead of the prefix-filtered hop list, so history day buckets agree with snapshot evaluation - reload_keys clears the decode cache: negatively-cached packets for a newly added channel key were permanently dropped by the normalizer Also documents 'sudo npx playwright install-deps chromium' in the AGENTS.md e2e setup.
78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
"""Tests for the API CLI command (server launch wiring)."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from click.testing import CliRunner
|
|
|
|
from meshcore_hub.api.cli import api
|
|
|
|
|
|
def test_api_default_runs_single_process():
|
|
"""With the default worker count, the app object is passed directly and no
|
|
worker/factory options are used."""
|
|
runner = CliRunner()
|
|
with patch("uvicorn.run") as mock_run:
|
|
result = runner.invoke(api, [], catch_exceptions=False)
|
|
|
|
assert result.exit_code == 0
|
|
assert mock_run.call_count == 1
|
|
args, kwargs = mock_run.call_args
|
|
# Single-process path passes the built app object, not an import string.
|
|
assert not isinstance(args[0], str)
|
|
assert "workers" not in kwargs
|
|
|
|
|
|
def test_api_workers_uses_env_factory_import_string():
|
|
"""workers > 1 launches uvicorn against the env-driven factory by import
|
|
string with the requested worker count."""
|
|
runner = CliRunner()
|
|
with patch("uvicorn.run") as mock_run:
|
|
result = runner.invoke(api, ["--workers", "3"], catch_exceptions=False)
|
|
|
|
assert result.exit_code == 0
|
|
args, kwargs = mock_run.call_args
|
|
assert args[0] == "meshcore_hub.api.app:create_app_from_env"
|
|
assert kwargs["workers"] == 3
|
|
assert kwargs["factory"] is True
|
|
|
|
|
|
def test_api_workers_from_env_var():
|
|
"""API_WORKERS env var drives the worker count (the Docker path)."""
|
|
runner = CliRunner()
|
|
with patch("uvicorn.run") as mock_run:
|
|
result = runner.invoke(
|
|
api, [], env={"API_WORKERS": "2"}, catch_exceptions=False
|
|
)
|
|
|
|
assert result.exit_code == 0
|
|
_, kwargs = mock_run.call_args
|
|
assert kwargs["workers"] == 2
|
|
|
|
|
|
def test_api_single_process_passes_spam_and_role_settings():
|
|
"""The single-process app must carry the env-configured spam + OIDC role
|
|
settings — previously this path dropped them, silently disabling the
|
|
spam hide-filter and custom role names (the env factory path was fine)."""
|
|
runner = CliRunner()
|
|
with patch("uvicorn.run") as mock_run:
|
|
result = runner.invoke(
|
|
api,
|
|
[],
|
|
env={
|
|
"SPAM_DETECTION_ENABLED": "true",
|
|
"SPAM_SCORE_THRESHOLD": "0.8",
|
|
"OIDC_ROLE_ADMIN": "superadmin",
|
|
"OIDC_ROLE_OPERATOR": "moderator",
|
|
"OIDC_ROLE_MEMBER": "user",
|
|
},
|
|
catch_exceptions=False,
|
|
)
|
|
|
|
assert result.exit_code == 0
|
|
app = mock_run.call_args[0][0]
|
|
assert app.state.spam_detection_enabled is True
|
|
assert app.state.spam_score_threshold == 0.8
|
|
assert app.state.oidc_role_admin == "superadmin"
|
|
assert app.state.oidc_role_operator == "moderator"
|
|
assert app.state.oidc_role_member == "user"
|