import unittest from datetime import timedelta from unittest.mock import AsyncMock, patch from backend.tests.test_insights import play, NOW, LIBRARIES from backend.tests.test_email_recaps import fixture_report from backend.app.services.insights import summarize from backend.app.services.email_recaps import illustrated_recap class ReportGraphicsTests(unittest.IsolatedAsyncioTestCase): def test_patterns_deduplicate_and_handle_empty_history(self): first = play() second = play("second", PlaybackDuration=1800, EpisodeId="episode", ActivityDateInserted=(NOW-timedelta(days=1)).isoformat()) report = summarize([first, first, second], LIBRARIES, NOW-timedelta(days=7), NOW) self.assertEqual(report["patterns"]["average_play_minutes"], 45) self.assertEqual(report["patterns"]["longest_play_minutes"], 60) self.assertEqual(report["patterns"]["weekend_percent"], 33.3) self.assertEqual(sum(r["minutes"] for r in report["patterns"]["media"]), 90) empty = summarize([], [], NOW-timedelta(days=7), NOW) self.assertEqual(empty["patterns"]["average_play_minutes"], 0) async def test_artwork_embedded_without_private_links_and_optional_on_failure(self): report = fixture_report() report["top_titles"][0]["artwork_url"] = "/insights/artwork/" + "a"*32 + "?token=123." + "b"*64 with patch("backend.app.services.email_recaps.get_runtime_settings"), patch("backend.app.services.insights_artwork.get_artwork", new=AsyncMock(return_value=(b"picture", "image/webp"))): rendered = await illustrated_recap(report, {"username":"viewer"}, "https://example.test", "https://example.test/unsubscribe") self.assertIn("cid:recap-title-0@magent", rendered["body_html"]) self.assertNotIn("?token=", rendered["body_html"]) self.assertEqual(rendered["inline_images"][0]["subtype"], "webp") preview = await illustrated_recap(report, {"username":"viewer"}, "https://example.test", "https://example.test/unsubscribe", preview=True) self.assertIn("data:image/webp;base64,", preview["body_html"]) self.assertNotIn("inline_images", preview) with patch("backend.app.services.email_recaps.get_runtime_settings"), patch("backend.app.services.insights_artwork.get_artwork", new=AsyncMock(side_effect=RuntimeError())): rendered = await illustrated_recap(report, {"username":"viewer"}, "https://example.test", "https://example.test/unsubscribe") self.assertEqual(rendered["inline_images"], [])