main
py 159 lines 4.6 KB
Raw
1 import asyncio
2 from datetime import datetime, timezone
3 from pathlib import Path
4 import sys
5 from types import SimpleNamespace
6
7 PROJECT_ROOT = Path(__file__).resolve().parents[1]
8 if str(PROJECT_ROOT) not in sys.path:
9 sys.path.insert(0, str(PROJECT_ROOT))
10
11 from helpers import task_scheduler
12 from helpers.task_scheduler import AdHocTask, ScheduledTask, TaskSchedule
13
14
15 class FixedDateTime(datetime):
16 @classmethod
17 def now(cls, tz=None):
18 value = cls(2026, 5, 9, 10, 0, tzinfo=timezone.utc)
19 if tz is None:
20 return value.replace(tzinfo=None)
21 return value.astimezone(tz)
22
23
24 def test_scheduled_task_next_run_uses_schedule_timezone(monkeypatch):
25 monkeypatch.setattr(task_scheduler, "datetime", FixedDateTime)
26 task = ScheduledTask.create(
27 name="rome morning",
28 system_prompt="",
29 prompt="remind me",
30 schedule=TaskSchedule(
31 minute="30",
32 hour="9",
33 day="10",
34 month="5",
35 weekday="*",
36 timezone="Europe/Rome",
37 ),
38 timezone="Europe/Rome",
39 )
40
41 assert task.get_next_run() == datetime(2026, 5, 10, 7, 30, tzinfo=timezone.utc)
42
43
44 def test_scheduled_task_normalizes_legacy_local_timezone(monkeypatch):
45 monkeypatch.setattr(task_scheduler, "datetime", FixedDateTime)
46 monkeypatch.setattr(
47 task_scheduler,
48 "Localization",
49 SimpleNamespace(get=lambda: SimpleNamespace(get_timezone=lambda: "Europe/Rome")),
50 )
51 task = ScheduledTask.create(
52 name="legacy local",
53 system_prompt="",
54 prompt="remind me",
55 schedule=TaskSchedule(
56 minute="30",
57 hour="9",
58 day="10",
59 month="5",
60 weekday="*",
61 timezone="local",
62 ),
63 )
64
65 assert task.schedule.timezone == "Europe/Rome"
66 assert task.get_next_run() == datetime(2026, 5, 10, 7, 30, tzinfo=timezone.utc)
67
68
69 def test_scheduler_missing_dedicated_context_logs_info(monkeypatch):
70 calls = []
71
72 class FakePrintStyle:
73 @staticmethod
74 def info(message):
75 calls.append(("info", message))
76
77 @staticmethod
78 def warning(message):
79 calls.append(("warning", message))
80
81 class FakeAgentContext:
82 @staticmethod
83 def get(_context_id):
84 return None
85
86 def __init__(self, _config, id, name):
87 self.id = id
88 self.name = name
89
90 monkeypatch.setattr(task_scheduler, "PrintStyle", FakePrintStyle)
91 monkeypatch.setattr(task_scheduler, "AgentContext", FakeAgentContext)
92 monkeypatch.setattr(task_scheduler, "initialize_agent", lambda: object())
93 monkeypatch.setattr(task_scheduler, "save_tmp_chat", lambda _context: None)
94 monkeypatch.setattr(
95 task_scheduler.projects, "activate_project", lambda *_args, **_kwargs: None
96 )
97
98 task = AdHocTask.create(
99 name="dedicated",
100 system_prompt="",
101 prompt="run this",
102 token="123",
103 )
104 scheduler = object.__new__(task_scheduler.TaskScheduler)
105
106 context = asyncio.run(scheduler._get_chat_context(task))
107
108 assert context.id == task.context_id
109 assert len(calls) == 1
110 level, message = calls[0]
111 assert level == "info"
112 assert "creating dedicated context" in message
113
114
115 def test_scheduler_missing_shared_context_still_logs_warning(monkeypatch):
116 calls = []
117
118 class FakePrintStyle:
119 @staticmethod
120 def info(message):
121 calls.append(("info", message))
122
123 @staticmethod
124 def warning(message):
125 calls.append(("warning", message))
126
127 class FakeAgentContext:
128 @staticmethod
129 def get(_context_id):
130 return None
131
132 def __init__(self, _config, id, name):
133 self.id = id
134 self.name = name
135
136 monkeypatch.setattr(task_scheduler, "PrintStyle", FakePrintStyle)
137 monkeypatch.setattr(task_scheduler, "AgentContext", FakeAgentContext)
138 monkeypatch.setattr(task_scheduler, "initialize_agent", lambda: object())
139 monkeypatch.setattr(task_scheduler, "save_tmp_chat", lambda _context: None)
140 monkeypatch.setattr(
141 task_scheduler.projects, "activate_project", lambda *_args, **_kwargs: None
142 )
143
144 task = AdHocTask.create(
145 name="shared",
146 system_prompt="",
147 prompt="run this",
148 token="123",
149 context_id="shared-context",
150 )
151 scheduler = object.__new__(task_scheduler.TaskScheduler)
152
153 context = asyncio.run(scheduler._get_chat_context(task))
154
155 assert context.id == task.context_id
156 assert len(calls) == 1
157 level, message = calls[0]
158 assert level == "warning"
159 assert "context not found" in message