dy-dashboard/tests/test_inventory_board_stale_cache.py
2026-10-28 11:14:17 +08:00

73 lines
3.6 KiB
Python

"""库存数据看板旧缓存立即返回与后台刷新回归测试。"""
import importlib
import json
import unittest
from datetime import date, datetime, timedelta
from pathlib import Path
from unittest import mock
class InventoryBoardStaleCacheTest(unittest.TestCase):
def test_expired_shared_cache_returns_immediately_and_starts_refresh(self):
from routes import dashboard
stale = {
'month': '2026-08',
'latest_date': '2026-08-31',
'all_amount': 123.0,
}
old_time = datetime.now() - timedelta(hours=2)
def fake_query(sql, params=None):
normalized = ' '.join(str(sql).split()).lower()
if normalized.startswith('select count(*) as row_count'):
return [{'row_count': 10, 'qty_sum': 20, 'updated_signature': 'sig'}]
if normalized.startswith('create table if not exists inventory_board_system_cache'):
return 0
if normalized.startswith('select payload, updated_at from inventory_board_system_cache'):
return [{'payload': json.dumps(stale), 'updated_at': old_time}]
raise AssertionError('旧缓存命中后不应继续执行冷计算SQL: ' + normalized[:120])
with mock.patch.object(dashboard, 'query', side_effect=fake_query), \
mock.patch.object(dashboard, 'cache_get', return_value=None), \
mock.patch.object(dashboard, 'cache_set') as cache_set, \
mock.patch.object(dashboard, '_start_inventory_board_system_refresh', return_value=True) as refresh:
result = dashboard._inventory_board_system('2026-08', date(2026, 8, 31))
self.assertEqual(123.0, result['all_amount'])
self.assertEqual('stale_refreshing', result['system_cache_state'])
self.assertEqual(old_time.strftime('%Y-%m-%d %H:%M:%S'), result['data_updated_at'])
refresh.assert_called_once()
cache_set.assert_called_once()
self.assertEqual(60, cache_set.call_args.kwargs['ttl'])
def test_fresh_process_cache_does_not_start_refresh(self):
from routes import dashboard
fresh = {'all_amount': 456.0, 'system_cache_state': 'fresh'}
with mock.patch.object(dashboard, 'query', return_value=[{
'row_count': 10, 'qty_sum': 20, 'updated_signature': 'sig'}]), \
mock.patch.object(dashboard, 'cache_get', return_value=fresh), \
mock.patch.object(dashboard, '_start_inventory_board_system_refresh') as refresh:
result = dashboard._inventory_board_system('2026-08', date(2026, 8, 31))
self.assertIs(fresh, result)
refresh.assert_not_called()
def test_force_refresh_bypasses_process_and_shared_cache_checks(self):
source = Path(__file__).resolve().parents[1].joinpath('routes', 'dashboard.py').read_text(encoding='utf-8')
self.assertIn('def _inventory_board_system(month, latest_date, force_refresh=False):', source)
self.assertIn('if not force_refresh:\n _cached = cache_get(_cache_key)', source)
self.assertIn('return inventory_board_stats(force_system_refresh=True)', source)
def test_frontend_shows_refresh_state_and_polls_silently(self):
app_js = Path(__file__).resolve().parents[1].joinpath('static', 'js', 'app.js').read_text(encoding='utf-8')
self.assertIn('invBoardCacheStatus', app_js)
self.assertIn('正在后台更新,当前先展示上次统计', app_js)
self.assertIn('scheduleInventoryBoardFreshPoll(d)', app_js)
self.assertIn('window._inventoryBoardRefreshAttempts > 12', app_js)
if __name__ == '__main__':
unittest.main()