|
|
|
|
@ -43,6 +43,7 @@ def storage_manager_mock():
|
|
|
|
|
"""构造默认可用的 StorageManager mock。"""
|
|
|
|
|
manager = MagicMock()
|
|
|
|
|
manager.is_available.return_value = True
|
|
|
|
|
manager.save_market_data_with_timestamp.return_value = True
|
|
|
|
|
manager.save_market_data.return_value = True
|
|
|
|
|
manager.save_symbol_timestamp.return_value = True
|
|
|
|
|
manager.get_market_data.return_value = None
|
|
|
|
|
@ -99,15 +100,20 @@ class TestSaveMarketData:
|
|
|
|
|
"""save_market_data 双写与降级测试。"""
|
|
|
|
|
|
|
|
|
|
def test_uses_storage_manager_when_available(self, db, sample_data, storage_manager_mock):
|
|
|
|
|
"""StorageManager 可用时优先写入存储层,并同步更新时间戳,返回代表记录。"""
|
|
|
|
|
"""StorageManager 可用时通过原子方法写入行情数据与时间戳,并返回代表记录。"""
|
|
|
|
|
with patch("app.services.cache.get_storage_manager", return_value=storage_manager_mock):
|
|
|
|
|
from app.services import cache
|
|
|
|
|
|
|
|
|
|
result = cache.save_market_data(db, "AG2606", sample_data)
|
|
|
|
|
|
|
|
|
|
storage_manager_mock.is_available.assert_called_once()
|
|
|
|
|
storage_manager_mock.save_market_data.assert_called_once_with("AG2606", sample_data)
|
|
|
|
|
storage_manager_mock.save_symbol_timestamp.assert_called_once()
|
|
|
|
|
storage_manager_mock.save_market_data_with_timestamp.assert_called_once()
|
|
|
|
|
call_args = storage_manager_mock.save_market_data_with_timestamp.call_args[0]
|
|
|
|
|
assert call_args[0] == "AG2606"
|
|
|
|
|
assert call_args[1] == sample_data
|
|
|
|
|
assert isinstance(call_args[2], datetime)
|
|
|
|
|
storage_manager_mock.save_market_data.assert_not_called()
|
|
|
|
|
storage_manager_mock.save_symbol_timestamp.assert_not_called()
|
|
|
|
|
assert isinstance(result, MarketData)
|
|
|
|
|
assert result.symbol == "AG2606"
|
|
|
|
|
assert result.data_type == "futures"
|
|
|
|
|
@ -136,21 +142,22 @@ class TestSaveMarketData:
|
|
|
|
|
|
|
|
|
|
def test_falls_back_to_sqlite_when_storage_save_fails(self, db, sample_data, storage_manager_mock):
|
|
|
|
|
"""StorageManager 写入失败时降级到 SQLite 写入。"""
|
|
|
|
|
storage_manager_mock.save_market_data.return_value = False
|
|
|
|
|
storage_manager_mock.save_market_data_with_timestamp.return_value = False
|
|
|
|
|
|
|
|
|
|
with patch("app.services.cache.get_storage_manager", return_value=storage_manager_mock):
|
|
|
|
|
from app.services import cache
|
|
|
|
|
|
|
|
|
|
result = cache.save_market_data(db, "AG2606", sample_data)
|
|
|
|
|
|
|
|
|
|
storage_manager_mock.save_market_data.assert_called_once()
|
|
|
|
|
storage_manager_mock.save_market_data_with_timestamp.assert_called_once()
|
|
|
|
|
storage_manager_mock.save_market_data.assert_not_called()
|
|
|
|
|
storage_manager_mock.save_symbol_timestamp.assert_not_called()
|
|
|
|
|
assert isinstance(result, MarketData)
|
|
|
|
|
assert db.query(MarketData).filter_by(symbol="AG2606").count() == 2
|
|
|
|
|
|
|
|
|
|
def test_falls_back_to_sqlite_when_storage_raises(self, db, sample_data, storage_manager_mock, caplog):
|
|
|
|
|
"""StorageManager 写入异常时降级到 SQLite 写入并记录警告。"""
|
|
|
|
|
storage_manager_mock.save_market_data.side_effect = Exception("storage down")
|
|
|
|
|
storage_manager_mock.save_market_data_with_timestamp.side_effect = Exception("storage down")
|
|
|
|
|
|
|
|
|
|
with patch("app.services.cache.get_storage_manager", return_value=storage_manager_mock):
|
|
|
|
|
from app.services import cache
|
|
|
|
|
@ -158,6 +165,9 @@ class TestSaveMarketData:
|
|
|
|
|
with caplog.at_level(logging.WARNING, logger="app.services.cache"):
|
|
|
|
|
result = cache.save_market_data(db, "AG2606", sample_data)
|
|
|
|
|
|
|
|
|
|
storage_manager_mock.save_market_data_with_timestamp.assert_called_once()
|
|
|
|
|
storage_manager_mock.save_market_data.assert_not_called()
|
|
|
|
|
storage_manager_mock.save_symbol_timestamp.assert_not_called()
|
|
|
|
|
assert isinstance(result, MarketData)
|
|
|
|
|
assert db.query(MarketData).filter_by(symbol="AG2606").count() == 2
|
|
|
|
|
assert "StorageManager 写入失败" in caplog.text
|
|
|
|
|
|