Skip to content

Commit 4500826

Browse files
Merge pull request #1993 from gitautoai/gitauto/issue-1992-20251201-000024-g9kg
Schedule: Add unit tests to services/supabase/llm_requests/clear_old_content.py
2 parents 9b5cf6e + d0f8095 commit 4500826

File tree

1 file changed

+386
-0
lines changed

1 file changed

+386
-0
lines changed
Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
from datetime import datetime, timedelta
2+
from unittest.mock import Mock, patch
3+
4+
from services.supabase.llm_requests.clear_old_content import clear_old_content
5+
6+
7+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
8+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
9+
def test_clear_old_content_success_default_retention(mock_datetime, mock_supabase):
10+
"""Test successful clearing of old content with default retention days (14)."""
11+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
12+
mock_datetime.now.return_value = fixed_now
13+
expected_cutoff = (fixed_now - timedelta(days=14)).isoformat()
14+
15+
mock_result = Mock()
16+
mock_result.data = [
17+
{"id": 1, "created_at": "2025-11-10T12:00:00"},
18+
{"id": 2, "created_at": "2025-11-11T12:00:00"},
19+
]
20+
21+
mock_table = Mock()
22+
mock_update = Mock()
23+
mock_lt = Mock()
24+
25+
mock_supabase.table.return_value = mock_table
26+
mock_table.update.return_value = mock_update
27+
mock_update.lt.return_value = mock_lt
28+
mock_lt.execute.return_value = mock_result
29+
30+
result = clear_old_content()
31+
32+
assert result == mock_result.data
33+
mock_supabase.table.assert_called_with("llm_requests")
34+
mock_table.update.assert_called_with({"input_content": "", "output_content": ""})
35+
mock_update.lt.assert_called_with("created_at", expected_cutoff)
36+
mock_lt.execute.assert_called_once()
37+
38+
39+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
40+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
41+
def test_clear_old_content_custom_retention_days(mock_datetime, mock_supabase):
42+
"""Test clearing old content with custom retention days."""
43+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
44+
mock_datetime.now.return_value = fixed_now
45+
retention_days = 30
46+
expected_cutoff = (fixed_now - timedelta(days=retention_days)).isoformat()
47+
48+
mock_result = Mock()
49+
mock_result.data = [{"id": 3, "created_at": "2025-10-15T12:00:00"}]
50+
51+
mock_table = Mock()
52+
mock_update = Mock()
53+
mock_lt = Mock()
54+
55+
mock_supabase.table.return_value = mock_table
56+
mock_table.update.return_value = mock_update
57+
mock_update.lt.return_value = mock_lt
58+
mock_lt.execute.return_value = mock_result
59+
60+
result = clear_old_content(retention_days=retention_days)
61+
62+
assert result == mock_result.data
63+
mock_supabase.table.assert_called_with("llm_requests")
64+
mock_update.lt.assert_called_with("created_at", expected_cutoff)
65+
66+
67+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
68+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
69+
def test_clear_old_content_no_data_to_clear(mock_datetime, mock_supabase):
70+
"""Test when no old content is found to clear."""
71+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
72+
mock_datetime.now.return_value = fixed_now
73+
74+
mock_result = Mock()
75+
mock_result.data = []
76+
77+
mock_table = Mock()
78+
mock_update = Mock()
79+
mock_lt = Mock()
80+
81+
mock_supabase.table.return_value = mock_table
82+
mock_table.update.return_value = mock_update
83+
mock_update.lt.return_value = mock_lt
84+
mock_lt.execute.return_value = mock_result
85+
86+
result = clear_old_content()
87+
88+
assert result is None
89+
mock_supabase.table.assert_called_with("llm_requests")
90+
91+
92+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
93+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
94+
def test_clear_old_content_result_data_is_none(mock_datetime, mock_supabase):
95+
"""Test when result.data is None."""
96+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
97+
mock_datetime.now.return_value = fixed_now
98+
99+
mock_result = Mock()
100+
mock_result.data = None
101+
102+
mock_table = Mock()
103+
mock_update = Mock()
104+
mock_lt = Mock()
105+
106+
mock_supabase.table.return_value = mock_table
107+
mock_table.update.return_value = mock_update
108+
mock_update.lt.return_value = mock_lt
109+
mock_lt.execute.return_value = mock_result
110+
111+
result = clear_old_content()
112+
113+
assert result is None
114+
mock_supabase.table.assert_called_with("llm_requests")
115+
116+
117+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
118+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
119+
def test_clear_old_content_zero_retention_days(mock_datetime, mock_supabase):
120+
"""Test clearing content with zero retention days (clear all)."""
121+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
122+
mock_datetime.now.return_value = fixed_now
123+
expected_cutoff = fixed_now.isoformat()
124+
125+
mock_result = Mock()
126+
mock_result.data = [{"id": 4}, {"id": 5}]
127+
128+
mock_table = Mock()
129+
mock_update = Mock()
130+
mock_lt = Mock()
131+
132+
mock_supabase.table.return_value = mock_table
133+
mock_table.update.return_value = mock_update
134+
mock_update.lt.return_value = mock_lt
135+
mock_lt.execute.return_value = mock_result
136+
137+
result = clear_old_content(retention_days=0)
138+
139+
assert result == mock_result.data
140+
mock_supabase.table.assert_called_with("llm_requests")
141+
mock_update.lt.assert_called_with("created_at", expected_cutoff)
142+
143+
144+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
145+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
146+
def test_clear_old_content_large_retention_days(mock_datetime, mock_supabase):
147+
"""Test clearing content with large retention days (e.g., 365 days)."""
148+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
149+
mock_datetime.now.return_value = fixed_now
150+
151+
mock_result = Mock()
152+
mock_result.data = [{"id": 7}]
153+
154+
mock_table = Mock()
155+
mock_update = Mock()
156+
mock_lt = Mock()
157+
158+
mock_supabase.table.return_value = mock_table
159+
mock_table.update.return_value = mock_update
160+
mock_update.lt.return_value = mock_lt
161+
mock_lt.execute.return_value = mock_result
162+
163+
result = clear_old_content(retention_days=365)
164+
165+
assert result == mock_result.data
166+
mock_supabase.table.assert_called_with("llm_requests")
167+
168+
169+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
170+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
171+
def test_clear_old_content_negative_retention_days(mock_datetime, mock_supabase):
172+
"""Test clearing content with negative retention days (future dates - edge case)."""
173+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
174+
mock_datetime.now.return_value = fixed_now
175+
expected_cutoff = (fixed_now - timedelta(days=-7)).isoformat()
176+
177+
mock_result = Mock()
178+
mock_result.data = []
179+
180+
mock_table = Mock()
181+
mock_update = Mock()
182+
mock_lt = Mock()
183+
184+
mock_supabase.table.return_value = mock_table
185+
mock_table.update.return_value = mock_update
186+
mock_update.lt.return_value = mock_lt
187+
mock_lt.execute.return_value = mock_result
188+
189+
result = clear_old_content(retention_days=-7)
190+
191+
assert result is None
192+
mock_supabase.table.assert_called_with("llm_requests")
193+
mock_update.lt.assert_called_with("created_at", expected_cutoff)
194+
195+
196+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
197+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
198+
def test_clear_old_content_database_exception(mock_datetime, mock_supabase):
199+
"""Test handling of database exceptions (decorator should catch and return None)."""
200+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
201+
mock_datetime.now.return_value = fixed_now
202+
203+
mock_table = Mock()
204+
mock_supabase.table.return_value = mock_table
205+
mock_table.update.side_effect = Exception("Database connection error")
206+
207+
result = clear_old_content()
208+
209+
assert result is None
210+
mock_supabase.table.assert_called_with("llm_requests")
211+
212+
213+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
214+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
215+
def test_clear_old_content_attribute_error(mock_datetime, mock_supabase):
216+
"""Test handling of AttributeError (decorator should catch and return None)."""
217+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
218+
mock_datetime.now.return_value = fixed_now
219+
220+
mock_table = Mock()
221+
mock_update = Mock()
222+
mock_lt = Mock()
223+
224+
mock_supabase.table.return_value = mock_table
225+
mock_table.update.return_value = mock_update
226+
mock_update.lt.return_value = mock_lt
227+
mock_lt.execute.side_effect = AttributeError(
228+
"'NoneType' object has no attribute 'data'"
229+
)
230+
231+
result = clear_old_content()
232+
233+
assert result is None
234+
mock_supabase.table.assert_called_with("llm_requests")
235+
236+
237+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
238+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
239+
def test_clear_old_content_type_error(mock_datetime, mock_supabase):
240+
"""Test handling of TypeError (decorator should catch and return None)."""
241+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
242+
mock_datetime.now.return_value = fixed_now
243+
244+
mock_table = Mock()
245+
mock_update = Mock()
246+
247+
mock_supabase.table.return_value = mock_table
248+
mock_table.update.return_value = mock_update
249+
mock_update.lt.side_effect = TypeError("Invalid type for comparison")
250+
251+
result = clear_old_content()
252+
253+
assert result is None
254+
mock_supabase.table.assert_called_with("llm_requests")
255+
256+
257+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
258+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
259+
def test_clear_old_content_key_error(mock_datetime, mock_supabase):
260+
"""Test handling of KeyError (decorator should catch and return None)."""
261+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
262+
mock_datetime.now.return_value = fixed_now
263+
264+
mock_table = Mock()
265+
mock_update = Mock()
266+
mock_lt = Mock()
267+
268+
mock_supabase.table.return_value = mock_table
269+
mock_table.update.return_value = mock_update
270+
mock_update.lt.return_value = mock_lt
271+
mock_lt.execute.side_effect = KeyError("created_at")
272+
273+
result = clear_old_content()
274+
275+
assert result is None
276+
mock_supabase.table.assert_called_with("llm_requests")
277+
278+
279+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
280+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
281+
def test_clear_old_content_single_record(mock_datetime, mock_supabase):
282+
"""Test clearing a single old record."""
283+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
284+
mock_datetime.now.return_value = fixed_now
285+
286+
mock_result = Mock()
287+
mock_result.data = [{"id": 100, "created_at": "2025-11-01T12:00:00"}]
288+
289+
mock_table = Mock()
290+
mock_update = Mock()
291+
mock_lt = Mock()
292+
293+
mock_supabase.table.return_value = mock_table
294+
mock_table.update.return_value = mock_update
295+
mock_update.lt.return_value = mock_lt
296+
mock_lt.execute.return_value = mock_result
297+
298+
result = clear_old_content()
299+
300+
assert result == mock_result.data
301+
assert len(result) == 1
302+
mock_supabase.table.assert_called_with("llm_requests")
303+
304+
305+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
306+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
307+
def test_clear_old_content_multiple_records(mock_datetime, mock_supabase):
308+
"""Test clearing multiple old records."""
309+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
310+
mock_datetime.now.return_value = fixed_now
311+
312+
mock_result = Mock()
313+
mock_result.data = [
314+
{"id": 1, "created_at": "2025-11-01T12:00:00"},
315+
{"id": 2, "created_at": "2025-11-05T12:00:00"},
316+
{"id": 3, "created_at": "2025-11-10T12:00:00"},
317+
]
318+
319+
mock_table = Mock()
320+
mock_update = Mock()
321+
mock_lt = Mock()
322+
323+
mock_supabase.table.return_value = mock_table
324+
mock_table.update.return_value = mock_update
325+
mock_update.lt.return_value = mock_lt
326+
mock_lt.execute.return_value = mock_result
327+
328+
result = clear_old_content()
329+
330+
assert result == mock_result.data
331+
assert len(result) == 3
332+
mock_supabase.table.assert_called_with("llm_requests")
333+
334+
335+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
336+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
337+
def test_clear_old_content_verifies_update_payload(mock_datetime, mock_supabase):
338+
"""Test that the update payload contains correct empty strings."""
339+
fixed_now = datetime(2025, 12, 1, 12, 0, 0)
340+
mock_datetime.now.return_value = fixed_now
341+
342+
mock_result = Mock()
343+
mock_result.data = [{"id": 1}]
344+
345+
mock_table = Mock()
346+
mock_update = Mock()
347+
mock_lt = Mock()
348+
349+
mock_supabase.table.return_value = mock_table
350+
mock_table.update.return_value = mock_update
351+
mock_update.lt.return_value = mock_lt
352+
mock_lt.execute.return_value = mock_result
353+
354+
result = clear_old_content()
355+
356+
mock_table.update.assert_called_once_with(
357+
{"input_content": "", "output_content": ""}
358+
)
359+
assert result == mock_result.data
360+
361+
362+
@patch("services.supabase.llm_requests.clear_old_content.supabase")
363+
@patch("services.supabase.llm_requests.clear_old_content.datetime")
364+
def test_clear_old_content_verifies_cutoff_calculation(mock_datetime, mock_supabase):
365+
"""Test that the cutoff date is calculated correctly."""
366+
fixed_now = datetime(2025, 12, 15, 10, 30, 45)
367+
mock_datetime.now.return_value = fixed_now
368+
retention_days = 7
369+
expected_cutoff = (fixed_now - timedelta(days=retention_days)).isoformat()
370+
371+
mock_result = Mock()
372+
mock_result.data = [{"id": 1}]
373+
374+
mock_table = Mock()
375+
mock_update = Mock()
376+
mock_lt = Mock()
377+
378+
mock_supabase.table.return_value = mock_table
379+
mock_table.update.return_value = mock_update
380+
mock_update.lt.return_value = mock_lt
381+
mock_lt.execute.return_value = mock_result
382+
383+
result = clear_old_content(retention_days=retention_days)
384+
385+
mock_update.lt.assert_called_once_with("created_at", expected_cutoff)
386+
assert result == mock_result.data

0 commit comments

Comments
 (0)