28
28
logger .setLevel (logging .INFO )
29
29
30
30
31
- def test_no_token_provided (event_loop : AbstractEventLoop ) -> None :
31
+ def test_no_token_provided (
32
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
33
+ ) -> None :
32
34
"""when no token is provided, it raises an error"""
33
35
34
- kwargs : RescheduleParams = {
35
- "token" : None ,
36
- "filter" : "label:test" ,
37
- "rules" : None ,
38
- "dry_run" : True ,
39
- "time_zone" : "UTC" ,
40
- "schedule" : None ,
41
- }
36
+ reschedule_params ["token" ] = None
42
37
43
38
fake_api = FakeTodoistAPI ("" )
44
39
45
40
curr_datetime = datetime (2022 , 1 , 5 , 12 , 0 , 0 )
46
41
47
42
with set_env ({"RETRY_ATTEMPTS" : "1" }):
48
43
with pytest .raises (HTTPError , match = "401 Client Error: Unauthorized for url" ):
49
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
44
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
50
45
51
46
52
47
def test_passing_invalid_cron_string_raises_error (
53
48
event_loop : AbstractEventLoop ,
49
+ reschedule_params : RescheduleParams ,
54
50
) -> None :
55
51
"""when an invalid cron string is provided, it raises an error"""
56
52
57
- kwargs : RescheduleParams = {
58
- "token" : "VALID_TOKEN" ,
59
- "filter" : "" ,
60
- "rules" : None ,
61
- "dry_run" : False ,
62
- "time_zone" : "UTC" ,
63
- "schedule" : "invalid_cron_string" ,
64
- }
53
+ reschedule_params ["schedule" ] = "invalid_cron_string"
65
54
66
55
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
67
56
68
57
curr_datetime = datetime (2025 , 1 , 5 , 12 , 0 , 0 )
69
58
70
59
with set_env ({"RETRY_ATTEMPTS" : "1" }):
71
60
with pytest .raises (ValueError , match = "Invalid cron schedule." ):
72
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
61
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
73
62
74
63
75
- def test_no_filter_provided (event_loop : AbstractEventLoop ) -> None :
64
+ def test_no_filter_provided (
65
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
66
+ ) -> None :
76
67
"""when no filter is provided, it does nothing"""
77
68
78
- kwargs : RescheduleParams = {
79
- "token" : "VALID_TOKEN" ,
80
- "filter" : "" ,
81
- "rules" : None ,
82
- "dry_run" : False ,
83
- "time_zone" : "UTC" ,
84
- "schedule" : None ,
85
- }
69
+ reschedule_params ["filter" ] = ""
86
70
87
71
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
88
72
89
73
curr_datetime = datetime (2025 , 1 , 5 , 12 , 0 , 0 )
90
74
91
75
with set_env ({"RETRY_ATTEMPTS" : "1" }):
92
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
76
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
93
77
94
78
assert fake_api .update_task .call_count == 0
95
79
96
80
97
- def test_no_rules_provided (event_loop : asyncio .AbstractEventLoop ) -> None :
81
+ def test_no_rules_provided (
82
+ event_loop : asyncio .AbstractEventLoop , reschedule_params : RescheduleParams
83
+ ) -> None :
98
84
"""when no rules are provided, it reschedules all tasks to the current day"""
99
85
100
- kwargs : RescheduleParams = {
101
- "token" : "VALID_TOKEN" ,
102
- "filter" : "label:test" ,
103
- "rules" : None ,
104
- "dry_run" : False ,
105
- "time_zone" : "UTC" ,
106
- "schedule" : None ,
107
- }
108
-
109
86
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
110
87
111
88
task = build_task ()
@@ -114,24 +91,17 @@ def test_no_rules_provided(event_loop: asyncio.AbstractEventLoop) -> None:
114
91
curr_date = datetime (2025 , 1 , 5 , 0 , 0 , 0 ).date ()
115
92
116
93
with set_env ({"RETRY_ATTEMPTS" : "1" }):
117
- postpwn (fake_api , event_loop , curr_date , ** kwargs )
94
+ postpwn (fake_api , event_loop , curr_date , ** reschedule_params )
118
95
119
96
assert fake_api .update_task .call_count == 1
120
97
assert fake_api .update_task .call_args .kwargs ["due_date" ] == curr_date
121
98
122
99
123
- def test_datetime_is_preserved (event_loop : AbstractEventLoop ) -> None :
100
+ def test_datetime_is_preserved (
101
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
102
+ ) -> None :
124
103
"""when a task has a datetime due date, the specific time is preserved"""
125
104
126
- kwargs : RescheduleParams = {
127
- "token" : "VALID_TOKEN" ,
128
- "filter" : "label:test" ,
129
- "rules" : None ,
130
- "dry_run" : False ,
131
- "time_zone" : "UTC" ,
132
- "schedule" : None ,
133
- }
134
-
135
105
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
136
106
137
107
task = build_task (is_datetime = True )
@@ -140,23 +110,18 @@ def test_datetime_is_preserved(event_loop: AbstractEventLoop) -> None:
140
110
curr_datetime = datetime (2025 , 1 , 5 , 0 , 0 , 0 )
141
111
142
112
with set_env ({"RETRY_ATTEMPTS" : "1" }):
143
- postpwn (fake_api , event_loop , curr_date = curr_datetime , ** kwargs )
113
+ postpwn (fake_api , event_loop , curr_date = curr_datetime , ** reschedule_params )
144
114
145
115
assert fake_api .update_task .call_count == 1
146
116
assert fake_api .update_task .call_args .kwargs ["due_datetime" ] == curr_datetime
147
117
148
118
149
- def test_weight_exceeds_single_max_weight (event_loop : AbstractEventLoop ) -> None :
119
+ def test_weight_exceeds_single_max_weight (
120
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
121
+ ) -> None :
150
122
"""when a rule weight exceeds the singular max weight, it raises an error"""
151
123
152
- kwargs : RescheduleParams = {
153
- "token" : "VALID_TOKEN" ,
154
- "filter" : "label:test" ,
155
- "rules" : "tests/fixtures/excessive_single_max_weight_rules.json" ,
156
- "dry_run" : False ,
157
- "time_zone" : "UTC" ,
158
- "schedule" : None ,
159
- }
124
+ reschedule_params ["rules" ] = "tests/fixtures/excessive_single_max_weight_rules.json"
160
125
161
126
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
162
127
@@ -172,20 +137,15 @@ def test_weight_exceeds_single_max_weight(event_loop: AbstractEventLoop) -> None
172
137
ValueError ,
173
138
match = "Invalid rule config: @weight_two exceeds max weight 2" ,
174
139
):
175
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
140
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
176
141
177
142
178
- def test_weight_exceeds_daily_max_weight (event_loop : AbstractEventLoop ) -> None :
143
+ def test_weight_exceeds_daily_max_weight (
144
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
145
+ ) -> None :
179
146
"""when a rule exceeds one of the daily max weights, it raises an error"""
180
147
181
- kwargs : RescheduleParams = {
182
- "token" : "VALID_TOKEN" ,
183
- "filter" : "label:test" ,
184
- "rules" : "tests/fixtures/excessive_daily_max_weight_rules.json" ,
185
- "dry_run" : False ,
186
- "time_zone" : "UTC" ,
187
- "schedule" : None ,
188
- }
148
+ reschedule_params ["rules" ] = "tests/fixtures/excessive_daily_max_weight_rules.json"
189
149
190
150
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
191
151
@@ -201,20 +161,15 @@ def test_weight_exceeds_daily_max_weight(event_loop: AbstractEventLoop) -> None:
201
161
ValueError ,
202
162
match = "Invalid rule config: @weight_two exceeds max weight 6" ,
203
163
):
204
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
164
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
205
165
206
166
207
- def test_no_matching_label (event_loop : asyncio .AbstractEventLoop ) -> None :
167
+ def test_no_matching_label (
168
+ event_loop : asyncio .AbstractEventLoop , reschedule_params : RescheduleParams
169
+ ) -> None :
208
170
"""when tasks have no matching labels, they are not rescheduled"""
209
171
210
- kwargs : RescheduleParams = {
211
- "token" : "VALID_TOKEN" ,
212
- "filter" : "label:test" ,
213
- "rules" : "tests/fixtures/single_max_weight_rules.json" ,
214
- "dry_run" : False ,
215
- "time_zone" : "UTC" ,
216
- "schedule" : None ,
217
- }
172
+ reschedule_params ["rules" ] = "tests/fixtures/single_max_weight_rules.json"
218
173
219
174
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
220
175
@@ -226,23 +181,18 @@ def test_no_matching_label(event_loop: asyncio.AbstractEventLoop) -> None:
226
181
curr_datetime = datetime (2025 , 1 , 5 , 12 , 0 , 0 )
227
182
228
183
with set_env ({"RETRY_ATTEMPTS" : "1" }):
229
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
184
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
230
185
231
186
assert fake_api .update_task .call_count == 1
232
187
assert fake_api .update_task .call_args .args [0 ] == labeled_task .id
233
188
234
189
235
- def test_reschedule_with_rules (event_loop : AbstractEventLoop ) -> None :
190
+ def test_reschedule_with_rules (
191
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
192
+ ) -> None :
236
193
"""when rules are provided, it reschedules tasks using smart rescheduling, respecting max weight"""
237
194
238
- kwargs : RescheduleParams = {
239
- "token" : "VALID_TOKEN" ,
240
- "filter" : "label:test" ,
241
- "rules" : "tests/fixtures/single_max_weight_rules.json" ,
242
- "dry_run" : False ,
243
- "time_zone" : "UTC" ,
244
- "schedule" : None ,
245
- }
195
+ reschedule_params ["rules" ] = "tests/fixtures/single_max_weight_rules.json"
246
196
247
197
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
248
198
@@ -256,7 +206,7 @@ def test_reschedule_with_rules(event_loop: AbstractEventLoop) -> None:
256
206
curr_datetime = datetime (2025 , 1 , 5 , 0 , 0 , 0 )
257
207
258
208
with set_env ({"RETRY_ATTEMPTS" : "1" }):
259
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
209
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
260
210
261
211
assert fake_api .update_task .call_count == 4
262
212
@@ -304,17 +254,12 @@ def test_reschedule_with_rules(event_loop: AbstractEventLoop) -> None:
304
254
)
305
255
306
256
307
- def test_reschedule_with_priority (event_loop : AbstractEventLoop ) -> None :
257
+ def test_reschedule_with_priority (
258
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
259
+ ) -> None :
308
260
"""when tasks have different priorities, it prioritizes the higher priority tasks first for rescheduling"""
309
261
310
- kwargs : RescheduleParams = {
311
- "token" : "VALID_TOKEN" ,
312
- "filter" : "label:test" ,
313
- "rules" : "tests/fixtures/single_max_weight_rules.json" ,
314
- "dry_run" : False ,
315
- "time_zone" : "UTC" ,
316
- "schedule" : None ,
317
- }
262
+ reschedule_params ["rules" ] = "tests/fixtures/single_max_weight_rules.json"
318
263
319
264
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
320
265
@@ -330,7 +275,7 @@ def test_reschedule_with_priority(event_loop: AbstractEventLoop) -> None:
330
275
curr_datetime = datetime (2025 , 1 , 5 , 0 , 0 , 0 )
331
276
332
277
with set_env ({"RETRY_ATTEMPTS" : "1" }):
333
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
278
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
334
279
335
280
assert fake_api .update_task .call_count == 4
336
281
@@ -380,17 +325,12 @@ def test_reschedule_with_priority(event_loop: AbstractEventLoop) -> None:
380
325
)
381
326
382
327
383
- def test_reschedule_with_rules_and_daily_weight (event_loop : AbstractEventLoop ):
328
+ def test_reschedule_with_rules_and_daily_weight (
329
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
330
+ ):
384
331
"""when rules with a daily max weight are provided, it reschedules tasks using smart rescheduling, respecting the daily max weight"""
385
332
386
- kwargs : RescheduleParams = {
387
- "token" : "VALID_TOKEN" ,
388
- "filter" : "label:test" ,
389
- "rules" : "tests/fixtures/daily_max_weight_rules.json" ,
390
- "dry_run" : False ,
391
- "time_zone" : "UTC" ,
392
- "schedule" : None ,
393
- }
333
+ reschedule_params ["rules" ] = "tests/fixtures/daily_max_weight_rules.json"
394
334
395
335
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
396
336
@@ -404,7 +344,7 @@ def test_reschedule_with_rules_and_daily_weight(event_loop: AbstractEventLoop):
404
344
curr_datetime = datetime (2025 , 1 , 5 , 0 , 0 , 0 )
405
345
406
346
with set_env ({"RETRY_ATTEMPTS" : "1" }):
407
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
347
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
408
348
409
349
assert fake_api .update_task .call_count == 5
410
350
@@ -468,17 +408,12 @@ def test_reschedule_with_rules_and_daily_weight(event_loop: AbstractEventLoop):
468
408
)
469
409
470
410
471
- def test_dry_run_doesn_not_update_tasks (event_loop : AbstractEventLoop ) -> None :
411
+ def test_dry_run_doesn_not_update_tasks (
412
+ event_loop : AbstractEventLoop , reschedule_params : RescheduleParams
413
+ ) -> None :
472
414
"""when dry run is enabled, it does not reschedule tasks"""
473
415
474
- kwargs : RescheduleParams = {
475
- "token" : "VALID_TOKEN" ,
476
- "filter" : "label:test" ,
477
- "rules" : None ,
478
- "dry_run" : True ,
479
- "time_zone" : "UTC" ,
480
- "schedule" : None ,
481
- }
416
+ reschedule_params ["dry_run" ] = True
482
417
483
418
fake_api = FakeTodoistAPI ("VALID_TOKEN" )
484
419
@@ -488,6 +423,6 @@ def test_dry_run_doesn_not_update_tasks(event_loop: AbstractEventLoop) -> None:
488
423
curr_datetime = datetime (2025 , 1 , 5 , 12 , 0 , 0 )
489
424
490
425
with set_env ({"RETRY_ATTEMPTS" : "1" }):
491
- postpwn (fake_api , event_loop , curr_datetime , ** kwargs )
426
+ postpwn (fake_api , event_loop , curr_datetime , ** reschedule_params )
492
427
493
428
assert fake_api .update_task .call_count == 0
0 commit comments