Improve tests
All checks were successful
Test and build Docker image / docker (push) Successful in 1m40s
All checks were successful
Test and build Docker image / docker (push) Successful in 1m40s
This commit is contained in:
parent
cba35edb19
commit
c55610affa
11 changed files with 811 additions and 75 deletions
|
|
@ -1,6 +1,21 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import typing
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from discord_rss_bot.hoyolab_api import create_hoyolab_webhook
|
||||
from discord_rss_bot.hoyolab_api import extract_post_id_from_hoyolab_url
|
||||
from discord_rss_bot.hoyolab_api import fetch_hoyolab_post
|
||||
from discord_rss_bot.hoyolab_api import is_c3kay_feed
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from reader import Entry
|
||||
|
||||
|
||||
class TestExtractPostIdFromHoyolabUrl:
|
||||
|
|
@ -37,3 +52,197 @@ class TestExtractPostIdFromHoyolabUrl:
|
|||
|
||||
for url in test_cases:
|
||||
assert extract_post_id_from_hoyolab_url(url) is None # type: ignore
|
||||
|
||||
|
||||
def make_entry(link: str | None = "https://www.hoyolab.com/article/38588239") -> SimpleNamespace:
|
||||
feed: SimpleNamespace = SimpleNamespace(url="https://feeds.c3kay.de/hoyolab.xml")
|
||||
return SimpleNamespace(
|
||||
id="entry-123",
|
||||
link=link,
|
||||
feed=feed,
|
||||
)
|
||||
|
||||
|
||||
class TestIsC3KayFeed:
|
||||
def test_true_for_c3kay_feed(self) -> None:
|
||||
assert is_c3kay_feed("https://feeds.c3kay.de/rss") is True
|
||||
|
||||
def test_false_for_non_c3kay_feed(self) -> None:
|
||||
assert is_c3kay_feed("https://example.com/rss") is False
|
||||
|
||||
|
||||
class TestFetchHoyolabPost:
|
||||
@patch("discord_rss_bot.hoyolab_api.requests.get")
|
||||
def test_returns_none_for_empty_post_id(self, mock_get: MagicMock) -> None:
|
||||
assert fetch_hoyolab_post("") is None
|
||||
mock_get.assert_not_called()
|
||||
|
||||
@patch("discord_rss_bot.hoyolab_api.requests.get")
|
||||
def test_returns_post_data_for_success_response(self, mock_get: MagicMock) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"retcode": 0,
|
||||
"data": {
|
||||
"post": {
|
||||
"post_id": "38588239",
|
||||
"subject": "Event",
|
||||
},
|
||||
},
|
||||
}
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
result = fetch_hoyolab_post("38588239")
|
||||
|
||||
assert result == {"post_id": "38588239", "subject": "Event"}
|
||||
assert mock_get.call_args.args[0].endswith("post_id=38588239")
|
||||
|
||||
@patch("discord_rss_bot.hoyolab_api.logger")
|
||||
@patch("discord_rss_bot.hoyolab_api.requests.get")
|
||||
def test_returns_none_and_logs_warning_for_non_success_payload(
|
||||
self,
|
||||
mock_get: MagicMock,
|
||||
mock_logger: MagicMock,
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.text = "bad payload"
|
||||
mock_response.json.return_value = {
|
||||
"retcode": -1,
|
||||
"data": {},
|
||||
}
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
result = fetch_hoyolab_post("38588239")
|
||||
|
||||
assert result is None
|
||||
mock_logger.warning.assert_called_once()
|
||||
|
||||
@patch("discord_rss_bot.hoyolab_api.logger")
|
||||
@patch("discord_rss_bot.hoyolab_api.requests.get")
|
||||
def test_returns_none_and_logs_exception_on_request_error(
|
||||
self,
|
||||
mock_get: MagicMock,
|
||||
mock_logger: MagicMock,
|
||||
) -> None:
|
||||
mock_get.side_effect = requests.RequestException("network issue")
|
||||
|
||||
result = fetch_hoyolab_post("38588239")
|
||||
|
||||
assert result is None
|
||||
mock_logger.exception.assert_called_once()
|
||||
|
||||
|
||||
class TestCreateHoyolabWebhook:
|
||||
@patch("discord_rss_bot.hoyolab_api.requests.get")
|
||||
@patch("discord_rss_bot.hoyolab_api.DiscordEmbed")
|
||||
@patch("discord_rss_bot.hoyolab_api.DiscordWebhook")
|
||||
def test_builds_embed_webhook_with_full_post_data(
|
||||
self,
|
||||
mock_webhook_cls: MagicMock,
|
||||
mock_embed_cls: MagicMock,
|
||||
mock_requests_get: MagicMock,
|
||||
) -> None:
|
||||
webhook_instance = MagicMock()
|
||||
embed_instance = MagicMock()
|
||||
mock_webhook_cls.return_value = webhook_instance
|
||||
mock_embed_cls.return_value = embed_instance
|
||||
|
||||
video_response = MagicMock()
|
||||
video_response.ok = True
|
||||
video_response.content = b"video-bytes"
|
||||
mock_requests_get.return_value = video_response
|
||||
|
||||
post_data = {
|
||||
"post": {
|
||||
"subject": "Update 4.0",
|
||||
"content": json.dumps({"describe": "Patch notes"}),
|
||||
"desc": "fallback description",
|
||||
"structured_content": json.dumps(
|
||||
[{"insert": {"video": "https://www.youtube.com/embed/abc123_XY"}}],
|
||||
),
|
||||
"event_start_date": "1712000000",
|
||||
"event_end_date": "1712600000",
|
||||
"created_at": "1711000000",
|
||||
},
|
||||
"image_list": [{"url": "https://img.example.com/hero.jpg", "height": 1080, "width": 1920}],
|
||||
"video": {"url": "https://cdn.example.com/video.mp4"},
|
||||
"game": {"color": "#11AAFF"},
|
||||
"user": {"nickname": "Paimon", "avatar_url": "https://img.example.com/avatar.jpg"},
|
||||
"classification": {"name": "Official"},
|
||||
}
|
||||
|
||||
entry = make_entry(link=None)
|
||||
entry = typing.cast("Entry", entry)
|
||||
webhook = create_hoyolab_webhook("https://discord.test/webhook", entry, post_data)
|
||||
|
||||
assert webhook is webhook_instance
|
||||
mock_webhook_cls.assert_called_once_with(url="https://discord.test/webhook", rate_limit_retry=True)
|
||||
|
||||
embed_instance.set_title.assert_called_once_with("Update 4.0")
|
||||
embed_instance.set_url.assert_called_once_with("https://feeds.c3kay.de/hoyolab.xml")
|
||||
embed_instance.set_image.assert_called_once_with(
|
||||
url="https://img.example.com/hero.jpg",
|
||||
height=1080,
|
||||
width=1920,
|
||||
)
|
||||
embed_instance.set_color.assert_called_once_with("11AAFF")
|
||||
embed_instance.set_footer.assert_called_once_with(text="Official")
|
||||
embed_instance.add_embed_field.assert_any_call(name="Start", value="<t:1712000000:R>")
|
||||
embed_instance.add_embed_field.assert_any_call(name="End", value="<t:1712600000:R>")
|
||||
embed_instance.set_timestamp.assert_called_once_with(timestamp="1711000000")
|
||||
|
||||
webhook_instance.add_file.assert_called_once_with(file=b"video-bytes", filename="entry-123.mp4")
|
||||
webhook_instance.add_embed.assert_called_once_with(embed_instance)
|
||||
assert webhook_instance.content == "https://www.youtube.com/watch?v=abc123_XY"
|
||||
webhook_instance.remove_embeds.assert_called_once()
|
||||
|
||||
@patch("discord_rss_bot.hoyolab_api.requests.get")
|
||||
@patch("discord_rss_bot.hoyolab_api.DiscordEmbed")
|
||||
@patch("discord_rss_bot.hoyolab_api.DiscordWebhook")
|
||||
def test_handles_invalid_structured_content_without_removing_embeds(
|
||||
self,
|
||||
mock_webhook_cls: MagicMock,
|
||||
mock_embed_cls: MagicMock,
|
||||
mock_requests_get: MagicMock,
|
||||
) -> None:
|
||||
webhook_instance = MagicMock()
|
||||
embed_instance = MagicMock()
|
||||
mock_webhook_cls.return_value = webhook_instance
|
||||
mock_embed_cls.return_value = embed_instance
|
||||
mock_requests_get.return_value = MagicMock(ok=False)
|
||||
|
||||
post_data = {
|
||||
"post": {
|
||||
"subject": "News",
|
||||
"content": "{}",
|
||||
"structured_content": "not-json",
|
||||
},
|
||||
}
|
||||
|
||||
entry = make_entry()
|
||||
entry = typing.cast("Entry", entry)
|
||||
webhook = create_hoyolab_webhook("https://discord.test/webhook", entry, post_data)
|
||||
|
||||
assert webhook is webhook_instance
|
||||
webhook_instance.remove_embeds.assert_not_called()
|
||||
|
||||
|
||||
def test_extract_post_id_with_querystring() -> None:
|
||||
url = "https://www.hoyolab.com/article/38588239?utm_source=feed"
|
||||
assert extract_post_id_from_hoyolab_url(url) == "38588239"
|
||||
|
||||
|
||||
def test_extract_post_id_non_string_input_returns_none() -> None:
|
||||
assert extract_post_id_from_hoyolab_url(None) is None # type: ignore[arg-type]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("url", "expected"),
|
||||
[
|
||||
("https://feeds.c3kay.de/rss", True),
|
||||
("https://www.hoyolab.com/feed", False),
|
||||
],
|
||||
)
|
||||
def test_is_c3kay_feed_parametrized(*, url: str, expected: bool) -> None:
|
||||
assert is_c3kay_feed(url) is expected
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue