agilentics / boiler
"""The liveness endpoint, the session guard and CSRF - no application logic.

These are the tests that stay true whatever this app turns into, which is why
they are the ones the skeleton ships. Each asserts a property of the *default*,
so a route added later inherits it or fails here.
"""
import pytest

from tests.conftest import PASSWORD, csrf_for


def test_healthz_is_public(app_client):
    r = app_client.get("/healthz")
    assert r.status_code == 200
    assert r.get_json() == {"status": "ok"}


def test_health_alias(app_client):
    assert app_client.get("/health").status_code == 200


def test_api_requires_a_session(app_client):
    """An unauthenticated API call is a JSON 401, not an HTML redirect - a
    fetch() that receives a login page reports a parse error instead of the thing
    that actually happened."""
    r = app_client.get("/api/me")
    assert r.status_code == 401
    assert "error" in r.get_json()


def test_a_page_redirects_to_login(app_client):
    r = app_client.get("/")
    assert r.status_code == 302
    assert r.headers["Location"].endswith("/login")


def test_an_unknown_route_is_guarded_not_404(app_client):
    """The guard runs before routing, so a signed-out caller cannot probe which
    paths exist. This is the allowlist's whole point: protection is the default,
    not something each route opts into."""
    r = app_client.get("/api/something-nobody-has-written-yet")
    assert r.status_code == 401


def test_static_is_reachable_signed_out(app_client):
    assert app_client.get("/static/js/app.js").status_code == 200


def test_a_write_without_the_csrf_token_is_refused(account):
    client, _user, _org = account
    r = client.post("/api/password", json={"current": PASSWORD, "new": "x" * 14})
    assert r.status_code == 403
    assert "Stale page" in r.get_json()["error"]


def test_a_write_with_the_csrf_token_is_allowed(account):
    client, user, _org = account
    r = client.post("/api/password",
                    json={"current": PASSWORD, "new": "a-longer-new-password"},
                    headers={"X-CSRF-Token": csrf_for(client)})
    assert r.status_code == 200, r.get_json()


@pytest.mark.parametrize("path", ["/login", "/api/login", "/health", "/healthz"])
def test_the_allowlist_is_exactly_what_it_says(app_client, path):
    """Every public path is public because a comment in crud.PUBLIC_PATHS says
    why. If this list grows, that comment is the review."""
    from app.endpoints.crud import is_public

    assert is_public(path)