@@ -89,6 +89,9 @@ def _make_config(self, **overrides):
8989 "schedule_time" : "18:00" ,
9090 "schedule_run_immediately" : True ,
9191 "run_immediately" : True ,
92+ "agent_event_monitor_enabled" : False ,
93+ "agent_event_alert_rules_json" : "" ,
94+ "agent_event_monitor_interval_minutes" : 5 ,
9295 }
9396 defaults .update (overrides )
9497 return _DummyConfig (** defaults )
@@ -173,6 +176,93 @@ def fake_run_with_schedule(
173176 )
174177 run_full_analysis .assert_called_once_with (runtime_config , args , None )
175178
179+ def test_schedule_mode_registers_event_monitor_background_task (self ) -> None :
180+ args = self ._make_args (schedule = True )
181+ config = self ._make_config (
182+ schedule_enabled = False ,
183+ agent_event_monitor_enabled = True ,
184+ agent_event_monitor_interval_minutes = 7 ,
185+ )
186+ monitor = object ()
187+ scheduled_call = {}
188+
189+ def fake_run_with_schedule (
190+ task ,
191+ schedule_time ,
192+ run_immediately ,
193+ background_tasks = None ,
194+ schedule_time_provider = None ,
195+ ):
196+ scheduled_call ["schedule_time" ] = schedule_time
197+ scheduled_call ["run_immediately" ] = run_immediately
198+ scheduled_call ["background_tasks" ] = background_tasks or []
199+ scheduled_call ["resolved_schedule_time" ] = (
200+ schedule_time_provider () if schedule_time_provider is not None else None
201+ )
202+
203+ with patch ("main.parse_arguments" , return_value = args ), \
204+ patch ("main.get_config" , return_value = config ), \
205+ patch ("main._reload_runtime_config" , return_value = config ), \
206+ patch ("main._build_schedule_time_provider" , return_value = lambda : "18:00" ), \
207+ patch ("main.setup_logging" ), \
208+ patch ("main.run_full_analysis" ) as run_full_analysis , \
209+ patch ("src.agent.events.build_event_monitor_from_config" , return_value = monitor ) as build_monitor , \
210+ patch ("src.agent.events.run_event_monitor_once" , return_value = ["triggered" ]) as run_monitor , \
211+ patch ("src.scheduler.run_with_schedule" , side_effect = fake_run_with_schedule ):
212+ exit_code = main .main ()
213+
214+ self .assertEqual (exit_code , 0 )
215+ build_monitor .assert_called_once_with (config )
216+ run_full_analysis .assert_not_called ()
217+ self .assertEqual (scheduled_call ["schedule_time" ], "18:00" )
218+ self .assertEqual (scheduled_call ["run_immediately" ], True )
219+ self .assertEqual (scheduled_call ["resolved_schedule_time" ], "18:00" )
220+ self .assertEqual (len (scheduled_call ["background_tasks" ]), 1 )
221+ background_task = scheduled_call ["background_tasks" ][0 ]
222+ self .assertEqual (background_task ["name" ], "agent_event_monitor" )
223+ self .assertEqual (background_task ["interval_seconds" ], 7 * 60 )
224+ self .assertEqual (background_task ["run_immediately" ], True )
225+
226+ background_task ["task" ]()
227+
228+ run_monitor .assert_called_once_with (monitor )
229+
230+ def test_schedule_mode_skips_event_monitor_background_task_without_valid_rules (self ) -> None :
231+ args = self ._make_args (schedule = True )
232+ config = self ._make_config (
233+ schedule_enabled = False ,
234+ agent_event_monitor_enabled = True ,
235+ )
236+ scheduled_call = {}
237+
238+ def fake_run_with_schedule (
239+ task ,
240+ schedule_time ,
241+ run_immediately ,
242+ background_tasks = None ,
243+ schedule_time_provider = None ,
244+ ):
245+ scheduled_call ["background_tasks" ] = background_tasks or []
246+
247+ with patch ("main.parse_arguments" , return_value = args ), \
248+ patch ("main.get_config" , return_value = config ), \
249+ patch ("main._reload_runtime_config" , return_value = config ), \
250+ patch ("main._build_schedule_time_provider" , return_value = lambda : "18:00" ), \
251+ patch ("main.setup_logging" ), \
252+ patch ("main.run_full_analysis" ) as run_full_analysis , \
253+ patch ("main.logger.info" ) as info_log , \
254+ patch ("src.agent.events.build_event_monitor_from_config" , return_value = None ) as build_monitor , \
255+ patch ("src.agent.events.run_event_monitor_once" ) as run_monitor , \
256+ patch ("src.scheduler.run_with_schedule" , side_effect = fake_run_with_schedule ):
257+ exit_code = main .main ()
258+
259+ self .assertEqual (exit_code , 0 )
260+ build_monitor .assert_called_once_with (config )
261+ run_monitor .assert_not_called ()
262+ run_full_analysis .assert_not_called ()
263+ self .assertEqual (scheduled_call ["background_tasks" ], [])
264+ info_log .assert_any_call ("EventMonitor 已启用,但未加载到有效规则,跳过后台提醒任务" )
265+
176266 def test_check_notify_returns_before_other_modes (self ) -> None :
177267 args = self ._make_args (check_notify = True , serve = True , schedule = True , market_review = True )
178268 config = self ._make_config (webui_enabled = False )
0 commit comments