File indexing completed on 2026-07-22 09:42:05
0001 from unittest.mock import patch
0002
0003 from django.test import TestCase
0004
0005 from snapper_ai.models import CurrentComponent
0006
0007 from monitor_app.snapper_panda import publish_panda_activity
0008
0009
0010 ACTIVITY = {
0011 "jobs": {
0012 "total": 120,
0013 "by_status": {"finished": 70, "failed": 10, "running": 40},
0014 "by_user": [{"user": "not-published", "total": 120}],
0015 "by_site": [
0016 {
0017 "site": "SITE_A",
0018 "total": 100,
0019 "finished": 65,
0020 "failed": 5,
0021 "running": 30,
0022 },
0023 {
0024 "site": "SITE_B",
0025 "total": 20,
0026 "finished": 5,
0027 "failed": 5,
0028 "running": 10,
0029 },
0030 ],
0031 },
0032 "tasks": {
0033 "total": 8,
0034 "by_status": {"running": 5, "done": 3},
0035 "by_type": [
0036 {"type": "epicproduction", "count": 6},
0037 {"type": "stfprocessing", "count": 2},
0038 ],
0039 "by_user": [{"user": "not-published", "total": 8}],
0040 },
0041 }
0042
0043 IN_FLIGHT = [
0044 {"site": "SITE_A", "status": "activated", "jobs": 50, "cores": 50},
0045 {"site": "SITE_A", "status": "running", "jobs": 30, "cores": 60},
0046 {"site": "SITE_B", "status": "starting", "jobs": 10, "cores": 10},
0047 {"site": "SITE_B", "status": "running", "jobs": 10, "cores": 10},
0048 ]
0049
0050 IN_FLIGHT_TASKS = [
0051 {"site": "SITE_A", "status": "running", "tasks": 5},
0052 {"site": "SITE_B", "status": "ready", "tasks": 2},
0053 {"site": "SITE_B", "status": "running", "tasks": 1},
0054 ]
0055
0056
0057 class PandaPublicationTests(TestCase):
0058 @patch("monitor_app.snapper_panda._in_flight_task_activity")
0059 @patch("monitor_app.snapper_panda._in_flight_activity")
0060 @patch("monitor_app.snapper_panda.get_activity")
0061 def test_publishes_bounded_activity_without_user_or_record_detail(
0062 self,
0063 activity_query,
0064 in_flight_query,
0065 in_flight_task_query,
0066 ):
0067 activity_query.return_value = ACTIVITY
0068 in_flight_query.return_value = IN_FLIGHT
0069 in_flight_task_query.return_value = IN_FLIGHT_TASKS
0070
0071 first = publish_panda_activity()
0072 component = CurrentComponent.objects.get(scope="epicprod", name="panda")
0073 self.assertTrue(first.update.content_changed)
0074 self.assertEqual(component.revision, 1)
0075 self.assertEqual(component.data["window_hours"], 24)
0076 self.assertEqual(component.data["jobs"]["total_24h"], 120)
0077 self.assertEqual(
0078 component.data["jobs"]["in_flight_now"],
0079 {
0080 "total": 100,
0081 "by_status": {
0082 "activated": 50,
0083 "running": 40,
0084 "starting": 10,
0085 },
0086 "running_jobs": 40,
0087 "running_cores": 70,
0088 },
0089 )
0090 self.assertEqual(
0091 component.data["jobs"]["sites"]["SITE_A"]["failed_24h"],
0092 5,
0093 )
0094 self.assertEqual(
0095 component.data["jobs"]["sites"]["SITE_A"]["by_status_now"],
0096 {"activated": 50, "running": 30},
0097 )
0098 self.assertEqual(
0099 component.data["tasks"]["by_type_24h"],
0100 {"epicproduction": 6, "stfprocessing": 2},
0101 )
0102 self.assertEqual(
0103 component.data["tasks"]["in_flight_now"],
0104 {
0105 "total": 8,
0106 "by_status": {"ready": 2, "running": 6},
0107 },
0108 )
0109 self.assertEqual(
0110 component.data["tasks"]["sites"],
0111 {
0112 "SITE_A": {
0113 "in_flight_tasks_now": 5,
0114 "by_status_now": {"running": 5},
0115 },
0116 "SITE_B": {
0117 "in_flight_tasks_now": 3,
0118 "by_status_now": {"ready": 2, "running": 1},
0119 },
0120 },
0121 )
0122 self.assertNotIn("by_user", component.data["jobs"])
0123 self.assertNotIn("by_user", component.data["tasks"])
0124
0125 unchanged = publish_panda_activity()
0126 component.refresh_from_db()
0127 self.assertFalse(unchanged.update.content_changed)
0128 self.assertEqual(component.revision, 1)
0129
0130 in_flight_query.return_value = [
0131 {
0132 "site": "SITE_A",
0133 "status": "activated",
0134 "jobs": 50,
0135 "cores": 50,
0136 },
0137 {
0138 "site": "SITE_A",
0139 "status": "running",
0140 "jobs": 31,
0141 "cores": 62,
0142 },
0143 {
0144 "site": "SITE_B",
0145 "status": "starting",
0146 "jobs": 10,
0147 "cores": 10,
0148 },
0149 {
0150 "site": "SITE_B",
0151 "status": "running",
0152 "jobs": 10,
0153 "cores": 10,
0154 },
0155 ]
0156 changed = publish_panda_activity()
0157 component.refresh_from_db()
0158 self.assertTrue(changed.update.content_changed)
0159 self.assertEqual(component.revision, 2)
0160 self.assertEqual(
0161 component.data["jobs"]["in_flight_now"]["running_cores"],
0162 72,
0163 )