diff options
| author | Dennis Fink | 2026-08-09 14:15:29 +0200 |
|---|---|---|
| committer | Dennis Fink | 2026-08-09 14:15:29 +0200 |
| commit | e4a8194e6de25e8a48e2c61ce7f89a8159fd99d9 (patch) | |
| tree | 234f63980aba8fe3c8d03e7bc8959598bce7e790 /tests/test_views.py | |
| parent | f53c1136184d2afabfb1e5974e527229aa71939a (diff) | |
| download | webmentions-ssg-e4a8194e6de25e8a48e2c61ce7f89a8159fd99d9.tar.gz webmentions-ssg-e4a8194e6de25e8a48e2c61ce7f89a8159fd99d9.zip | |
Implement received Webmention handling
Add the Flask application setup, database models and migrations,
authentication, and configuration for development and testing.
Implement asynchronous Webmention verification with Huey, including HTML
and plain-text source validation, retries, status tracking, and size
limits.
Add status, login, and paginated received-Webmention views together with
comprehensive tests for forms, views, and receiver tasks.
Diffstat (limited to 'tests/test_views.py')
| -rw-r--r-- | tests/test_views.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/tests/test_views.py b/tests/test_views.py new file mode 100644 index 0000000..d7fd798 --- /dev/null +++ b/tests/test_views.py @@ -0,0 +1,183 @@ +import uuid +from types import ModuleType + +import pytest +import sqlalchemy as sa +from flask import Flask +from flask.testing import FlaskClient + +from webmentions_ssg import DATABASE as db +from webmentions_ssg.models import ReceivedWebmention + + +def test_endpoint_only_accepts_post( + client: FlaskClient, +) -> None: + response = client.get("/endpoint") + + assert response.status_code == 405 + + +def test_endpoint_returns_form_errors( + client: FlaskClient, +) -> None: + response = client.post( + "/endpoint", + data={ + "source": "https://source.example/post", + "target": "https://example.com/post", + }, + ) + + assert response.status_code == 400 + + errors = response.get_json() + + assert errors is not None + assert "target" in errors + + +def test_endpoint_creates_webmention( + app: Flask, + client: FlaskClient, + views_module: ModuleType, + monkeypatch: pytest.MonkeyPatch, +) -> None: + queued: list[uuid.UUID] = [] + + monkeypatch.setattr( + views_module, + "verify_webmention", + queued.append, + ) + + source = "https://source.example/post" + target = "https://dennisfink.me/blog/example/" + + response = client.post( + "/endpoint", + data={ + "source": source, + "target": target, + }, + ) + + assert response.status_code == 201 + + with app.app_context(): + webmention = db.session.scalar(sa.select(ReceivedWebmention)) + + assert webmention is not None + assert webmention.source == source + assert webmention.target == target + assert webmention.status == "received" + assert webmention.failure_reason is None + + identifier = webmention.uuid + + assert response.headers["Location"].endswith(str(identifier)) + + assert queued == [identifier] + + +def test_endpoint_is_idempotent( + app: Flask, + client: FlaskClient, + views_module: ModuleType, + monkeypatch: pytest.MonkeyPatch, +) -> None: + queued: list[uuid.UUID] = [] + + monkeypatch.setattr( + views_module, + "verify_webmention", + queued.append, + ) + + data = { + "source": ("https://source.example/post"), + "target": ("https://dennisfink.me/blog/example/"), + } + + first_response = client.post( + "/endpoint", + data=data, + ) + second_response = client.post( + "/endpoint", + data=data, + ) + + assert first_response.status_code == 201 + assert second_response.status_code == 201 + + assert first_response.headers["Location"] == second_response.headers["Location"] + + with app.app_context(): + webmentions = db.session.scalars(sa.select(ReceivedWebmention)).all() + + assert len(webmentions) == 1 + + webmention = webmentions[0] + + assert webmention.source == data["source"] + assert webmention.target == data["target"] + assert webmention.status == "received" + assert webmention.failure_reason is None + + identifier = webmention.uuid + + assert queued == [ + identifier, + identifier, + ] + + +def test_resending_resets_failure_state( + app: Flask, + client: FlaskClient, + views_module: ModuleType, + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setattr( + views_module, + "verify_webmention", + lambda identifier: None, + ) + + source = "https://source.example/post" + target = "https://dennisfink.me/blog/example/" + + with app.app_context(): + existing = ReceivedWebmention( + uuid=uuid.uuid7(), + source=source, + target=target, + status="failed", + failure_reason="Previous failure", + ) + + db.session.add(existing) + db.session.commit() + + identifier = existing.uuid + + response = client.post( + "/endpoint", + data={ + "source": source, + "target": target, + }, + ) + + assert response.status_code == 201 + + with app.app_context(): + webmention = db.session.get( + ReceivedWebmention, + identifier, + ) + + assert webmention is not None + assert webmention.status == "received" + assert webmention.failure_reason is None |
