aboutsummaryrefslogtreecommitdiff
path: root/tests/test_views.py
diff options
context:
space:
mode:
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