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, public_dns: None, ) -> 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, public_dns: None, ) -> 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, public_dns: None, ) -> 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