Fix invalid feeds persisting after failed initial update
All checks were successful
Test and build Docker image / docker (push) Successful in 27s

This commit is contained in:
Joakim Hellsén 2026-05-31 04:25:51 +02:00
commit 459df727a9
Signed by: Joakim Hellsén
SSH key fingerprint: SHA256:/9h/CsExpFp+PRhsfA0xznFx2CGfTT5R/kpuFfUgEQk
4 changed files with 107 additions and 30 deletions

View file

@ -15,6 +15,7 @@ from unittest.mock import patch
import pytest
from reader import EntryNotFoundError
from reader import Feed
from reader import FeedExistsError
from reader import FeedNotFoundError
from reader import Reader
from reader import StorageError
@ -448,6 +449,38 @@ def test_create_feed_falls_back_to_embed_when_global_delivery_mode_is_invalid()
reader.set_tag.assert_any_call("https://example.com/feed.xml", "should_send_embed", True)
def test_create_feed_removes_new_feed_when_initial_update_fails() -> None:
feed_url = "https://example.com/not-a-feed"
autodiscover_links = [{"href": "https://example.com/feed.xml", "type": "application/rss+xml"}]
reader = MagicMock()
reader.get_tag.side_effect = lambda resource, key, default=None: { # noqa: ARG005
"webhooks": [{"name": "Main", "url": "https://discord.com/api/webhooks/123/abc"}],
".reader.autodiscover": autodiscover_links,
}.get(key, default)
reader.update_feed.side_effect = StorageError("invalid feed")
with pytest.raises(feeds.FeedUpdateError) as exc_info:
create_feed(reader, feed_url, "Main")
reader.delete_feed.assert_called_once_with(feed_url)
assert exc_info.value.autodiscover_links == autodiscover_links
def test_create_feed_does_not_remove_existing_feed_when_update_fails() -> None:
feed_url = "https://example.com/existing-feed.xml"
reader = MagicMock()
reader.get_tag.side_effect = lambda resource, key, default=None: { # noqa: ARG005
"webhooks": [{"name": "Main", "url": "https://discord.com/api/webhooks/123/abc"}],
}.get(key, default)
reader.add_feed.side_effect = FeedExistsError(feed_url)
reader.update_feed.side_effect = StorageError("temporary failure")
with pytest.raises(feeds.FeedUpdateError):
create_feed(reader, feed_url, "Main")
reader.delete_feed.assert_not_called()
@patch("discord_rss_bot.feeds.capture_full_page_screenshot")
@patch("discord_rss_bot.feeds.DiscordWebhook")
def test_create_screenshot_webhook_adds_image_file(

View file

@ -199,8 +199,6 @@ def test_create_feed_suggests_autodiscovered_links() -> None:
return [{"name": webhook_name, "url": webhook_url}]
if resource == () and key == "delivery_mode":
return "embed"
if resource == submitted_url and key == ".reader.autodiscover":
return [{"href": discovered_url, "title": "Example feed", "type": "application/rss+xml"}]
return default
stub_reader.get_tag.side_effect = get_tag
@ -210,7 +208,17 @@ def test_create_feed_suggests_autodiscovered_links() -> None:
with patch.object(
main_module,
"create_feed",
side_effect=feeds.FeedUpdateError(status_code=404, detail="Error updating feed"),
side_effect=feeds.FeedUpdateError(
status_code=404,
detail="Error updating feed",
autodiscover_links=[
{
"href": discovered_url,
"title": "Example feed",
"type": "application/rss+xml",
}
],
),
):
response: Response = client.post(
url="/add",
@ -1034,31 +1042,23 @@ def test_change_feed_url_nonexistent_old_url_returns_404() -> None:
def test_change_feed_url_new_url_already_exists_returns_409() -> None:
"""Changing to a URL that is already tracked should return HTTP 409."""
second_feed_url = "https://lovinator.space/rss_test_small.xml"
second_feed_url = "https://example.com/existing.xml"
# Ensure both feeds are absent.
client.post(url="/remove", data={"feed_url": feed_url})
client.post(url="/remove", data={"feed_url": second_feed_url})
class StubReader:
def change_feed_url(self, _old_url: str, new_url: str) -> None:
raise feeds.FeedExistsError(new_url)
# Ensure webhook exists.
client.post(url="/delete_webhook", data={"webhook_url": webhook_url})
client.post(url="/add_webhook", data={"webhook_name": webhook_name, "webhook_url": webhook_url})
app.dependency_overrides[get_reader_dependency] = StubReader
try:
response: Response = client.post(
url="/change_feed_url",
data={"old_feed_url": feed_url, "new_feed_url": second_feed_url},
)
finally:
app.dependency_overrides = {}
# Add both feeds.
client.post(url="/add", data={"feed_url": feed_url, "webhook_dropdown": webhook_name})
client.post(url="/add", data={"feed_url": second_feed_url, "webhook_dropdown": webhook_name})
# Try to rename one to the other.
response: Response = client.post(
url="/change_feed_url",
data={"old_feed_url": feed_url, "new_feed_url": second_feed_url},
)
assert response.status_code == 409, f"Expected 409 when new URL already exists, got {response.status_code}"
# Cleanup.
client.post(url="/remove", data={"feed_url": feed_url})
client.post(url="/remove", data={"feed_url": second_feed_url})
def test_change_feed_url_same_url_redirects_without_error() -> None:
"""Changing a feed's URL to itself should redirect cleanly without any error."""