97 lines
3.7 KiB
Python
97 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from backend.features.alerts.service import AlertService
|
|
from database import ReviewDatabase
|
|
|
|
|
|
class AlertServiceTests(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.temp = tempfile.TemporaryDirectory()
|
|
self.database = ReviewDatabase(Path(self.temp.name) / "review.db")
|
|
self.owner = self.database.create_user("alert_owner", "salt", "hash")
|
|
self.other = self.database.create_user("alert_other", "salt", "hash")
|
|
self.service = AlertService(self.database)
|
|
|
|
def tearDown(self) -> None:
|
|
self.temp.cleanup()
|
|
|
|
def test_future_manual_alert_is_visible_but_not_unread_until_due(self):
|
|
alert_id = self.service.create_manual(
|
|
self.owner["id"],
|
|
{
|
|
"title": "复核承接",
|
|
"content": "开盘不及预期则退出观察",
|
|
"code": "002141",
|
|
"remind_date": "2026-07-25",
|
|
},
|
|
)
|
|
before = self.service.list_alerts(self.owner["id"], "all", "2026-07-22")
|
|
due = self.service.list_alerts(self.owner["id"], "unread", "2026-07-25")
|
|
|
|
self.assertEqual(before["items"][0]["id"], alert_id)
|
|
self.assertFalse(before["items"][0]["due"])
|
|
self.assertEqual(before["unread_count"], 0)
|
|
self.assertEqual(due["unread_count"], 1)
|
|
self.assertTrue(due["items"][0]["due"])
|
|
|
|
def test_alert_reads_and_mutations_are_scoped_to_owner(self):
|
|
alert_id = self.database.save_alert(
|
|
self.owner["id"], "manual", "甲的提醒", "", "20260722", "", "owner-only"
|
|
)
|
|
self.assertEqual(
|
|
self.service.list_alerts(self.other["id"], "all", "2026-07-22")["items"], []
|
|
)
|
|
self.assertFalse(self.database.mark_alert_read(self.other["id"], alert_id))
|
|
self.assertFalse(self.database.delete_alert(self.other["id"], alert_id))
|
|
self.assertTrue(self.database.mark_alert_read(self.owner["id"], alert_id))
|
|
self.assertEqual(
|
|
self.service.list_alerts(self.owner["id"], "all", "2026-07-22")["unread_count"], 0
|
|
)
|
|
self.assertTrue(self.database.delete_alert(self.owner["id"], alert_id))
|
|
|
|
def test_strategy_alerts_are_idempotent(self):
|
|
tracking = {
|
|
"batches": [
|
|
{
|
|
"run_id": 9,
|
|
"strategy_name": "修复策略",
|
|
"items": [{"code": "002141"}, {"code": "600000"}],
|
|
"summary": {
|
|
"observed": 2,
|
|
"completed": 2,
|
|
"t1_win_rate": 50.0,
|
|
"average_t5": 3.25,
|
|
},
|
|
}
|
|
]
|
|
}
|
|
self.service.sync_strategy_tracking(self.owner["id"], tracking)
|
|
self.service.sync_strategy_tracking(self.owner["id"], tracking)
|
|
alerts = self.database.list_alerts(
|
|
self.owner["id"], "99991231", unread_only=False
|
|
)
|
|
|
|
self.assertEqual(len(alerts), 2)
|
|
self.assertEqual({item["kind"] for item in alerts}, {"strategy_t1", "strategy_t5"})
|
|
|
|
def test_mark_all_only_changes_due_alerts(self):
|
|
self.database.save_alert(
|
|
self.owner["id"], "manual", "今日", "", "20260722", "", "due"
|
|
)
|
|
self.database.save_alert(
|
|
self.owner["id"], "manual", "未来", "", "20260723", "", "future"
|
|
)
|
|
self.assertEqual(
|
|
self.database.mark_all_alerts_read(self.owner["id"], "20260722"), 1
|
|
)
|
|
future = self.service.list_alerts(self.owner["id"], "unread", "2026-07-23")
|
|
self.assertEqual([item["title"] for item in future["items"]], ["未来"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|