fix: 跳过推荐空缓存

This commit is contained in:
jxxghp
2026-06-13 08:09:49 +08:00
parent 7d582cc4d8
commit ab9eeedb3e
2 changed files with 106 additions and 53 deletions

View File

@@ -1,42 +1,95 @@
import asyncio
from unittest import TestCase
from typing import Generator
from unittest.mock import AsyncMock, patch
import pytest
from app.chain.recommend import RecommendChain
from app.core.cache import TTLCache
class RecommendChainTest(TestCase):
def tearDown(self):
"""
清理推荐缓存,避免缓存装饰器状态影响其他用例。
"""
RecommendChain.tmdb_trending.cache_clear()
asyncio.run(RecommendChain.async_tmdb_trending.cache_clear())
TTLCache(region=RecommendChain.recommend_cache_region).clear()
SYNC_EMPTY_CACHE_CASES = [
("tmdb_movies", "app.chain.recommend.TmdbChain", "tmdb_discover"),
("tmdb_tvs", "app.chain.recommend.TmdbChain", "tmdb_discover"),
("tmdb_trending", "app.chain.recommend.TmdbChain", "tmdb_trending"),
("bangumi_calendar", "app.chain.recommend.BangumiChain", "calendar"),
("douban_movie_showing", "app.chain.recommend.DoubanChain", "movie_showing"),
("douban_movies", "app.chain.recommend.DoubanChain", "douban_discover"),
("douban_tvs", "app.chain.recommend.DoubanChain", "douban_discover"),
("douban_movie_top250", "app.chain.recommend.DoubanChain", "movie_top250"),
("douban_tv_weekly_chinese", "app.chain.recommend.DoubanChain", "tv_weekly_chinese"),
("douban_tv_weekly_global", "app.chain.recommend.DoubanChain", "tv_weekly_global"),
("douban_tv_animation", "app.chain.recommend.DoubanChain", "tv_animation"),
("douban_movie_hot", "app.chain.recommend.DoubanChain", "movie_hot"),
("douban_tv_hot", "app.chain.recommend.DoubanChain", "tv_hot"),
]
def test_tmdb_trending_does_not_cache_empty_result(self):
"""
TMDB流行趋势返回空列表时不应缓存避免一次接口异常后长时间固定为空。
"""
chain = RecommendChain()
with patch("app.chain.recommend.TmdbChain") as tmdb_chain:
tmdb_chain.return_value.tmdb_trending.side_effect = [[], []]
ASYNC_EMPTY_CACHE_CASES = [
("async_tmdb_movies", "app.chain.recommend.TmdbChain"),
("async_tmdb_tvs", "app.chain.recommend.TmdbChain"),
("async_tmdb_trending", "app.chain.recommend.TmdbChain"),
("async_bangumi_calendar", "app.chain.recommend.BangumiChain"),
("async_douban_movie_showing", "app.chain.recommend.DoubanChain"),
("async_douban_movies", "app.chain.recommend.DoubanChain"),
("async_douban_tvs", "app.chain.recommend.DoubanChain"),
("async_douban_movie_top250", "app.chain.recommend.DoubanChain"),
("async_douban_tv_weekly_chinese", "app.chain.recommend.DoubanChain"),
("async_douban_tv_weekly_global", "app.chain.recommend.DoubanChain"),
("async_douban_tv_animation", "app.chain.recommend.DoubanChain"),
("async_douban_movie_hot", "app.chain.recommend.DoubanChain"),
("async_douban_tv_hot", "app.chain.recommend.DoubanChain"),
]
self.assertEqual(chain.tmdb_trending(page=1), [])
self.assertEqual(chain.tmdb_trending(page=1), [])
self.assertEqual(tmdb_chain.return_value.tmdb_trending.call_count, 2)
def clear_recommend_cache() -> None:
"""清理推荐缓存,避免缓存装饰器状态影响用例。"""
TTLCache(region=RecommendChain.recommend_cache_region).clear()
def test_async_tmdb_trending_does_not_cache_empty_result(self):
"""
异步TMDB流行趋势返回空列表时也不应缓存。
"""
chain = RecommendChain()
with patch("app.chain.recommend.TmdbChain") as tmdb_chain:
tmdb_chain.return_value.async_run_module = AsyncMock(side_effect=[[], []])
self.assertEqual(asyncio.run(chain.async_tmdb_trending(page=1)), [])
self.assertEqual(asyncio.run(chain.async_tmdb_trending(page=1)), [])
@pytest.fixture(autouse=True)
def isolated_recommend_cache() -> Generator[None, None, None]:
"""每个用例前后都清空推荐缓存。"""
clear_recommend_cache()
yield
clear_recommend_cache()
self.assertEqual(tmdb_chain.return_value.async_run_module.call_count, 2)
@pytest.mark.parametrize(
("method_name", "chain_target", "backend_method"),
SYNC_EMPTY_CACHE_CASES,
)
def test_sync_recommend_methods_do_not_cache_empty_result(
method_name: str,
chain_target: str,
backend_method: str,
) -> None:
"""同步推荐来源返回空列表时不应缓存。"""
chain = RecommendChain()
recommend_method = getattr(chain, method_name)
with patch(chain_target) as backend_chain:
backend_call = getattr(backend_chain.return_value, backend_method)
backend_call.side_effect = [[], []]
assert recommend_method(page=1) == []
assert recommend_method(page=1) == []
assert backend_call.call_count == 2
@pytest.mark.parametrize(("method_name", "chain_target"), ASYNC_EMPTY_CACHE_CASES)
def test_async_recommend_methods_do_not_cache_empty_result(
method_name: str,
chain_target: str,
) -> None:
"""异步推荐来源返回空列表时不应缓存。"""
chain = RecommendChain()
recommend_method = getattr(chain, method_name)
with patch(chain_target) as backend_chain:
backend_chain.return_value.async_run_module = AsyncMock(side_effect=[[], []])
assert asyncio.run(recommend_method(page=1)) == []
assert asyncio.run(recommend_method(page=1)) == []
assert backend_chain.return_value.async_run_module.call_count == 2