aboutsummaryrefslogtreecommitdiff
path: root/tests/test_views.py
diff options
context:
space:
mode:
authorDennis Fink2026-08-09 14:15:29 +0200
committerDennis Fink2026-08-09 14:22:00 +0200
commit67eff0a854da010cb6ecd119d84238ec3e119272 (patch)
treec4a85592b957bb01fa62f79329faa6ba0823d9b3 /tests/test_views.py
parentf53c1136184d2afabfb1e5974e527229aa71939a (diff)
downloadwebmentions-ssg-67eff0a854da010cb6ecd119d84238ec3e119272.tar.gz
webmentions-ssg-67eff0a854da010cb6ecd119d84238ec3e119272.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.py183
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