Skip to content

Commit 6648586

Browse files
committed
test for TASK_PROCESSOR_MODE
- consistent usage of `settings.TASK_PROCESSOR_MODE` - test for failure running tasks when `TASK_PROCESSOR_MODE` is `False` - add `task_processor_mode` pytest marker - consistent usage of `django_db` marker
1 parent 5c38bbe commit 6648586

File tree

10 files changed

+121
-76
lines changed

10 files changed

+121
-76
lines changed

settings/dev.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
TASK_DELETE_RETENTION_DAYS = 15
4747
TASK_DELETE_RUN_EVERY = timedelta(days=1)
4848
TASK_DELETE_RUN_TIME = time(5, 0, 0)
49-
TASK_PROCESSOR_MODE = True
49+
TASK_PROCESSOR_MODE = False
5050
TASK_RUN_METHOD = TaskRunMethod.TASK_PROCESSOR
5151

5252
# Avoid models.W042 warnings

src/common/prometheus/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import importlib
12
import typing
23

34
import prometheus_client
@@ -16,3 +17,26 @@ def get_registry() -> prometheus_client.CollectorRegistry:
1617
registry = prometheus_client.CollectorRegistry()
1718
MultiProcessCollector(registry) # type: ignore[no-untyped-call]
1819
return registry
20+
21+
22+
def reload_metrics(*metric_module_names: str) -> None:
23+
"""
24+
Clear the registry of all collectors from the given modules
25+
and reload the modules to register the collectors again.
26+
27+
Used in tests to reset the state of the metrics module
28+
when needed.
29+
"""
30+
31+
for module_name in metric_module_names:
32+
metrics_module = importlib.import_module(module_name)
33+
34+
_collectors = metrics_module.__dict__.values()
35+
36+
for collector in [
37+
*(registry := prometheus_client.REGISTRY)._collector_to_names
38+
]:
39+
if collector in _collectors:
40+
registry.unregister(collector)
41+
42+
importlib.reload(metrics_module)

src/task_processor/decorators.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
import os
32
import typing
43
from datetime import datetime, time, timedelta
54
from threading import Thread
@@ -178,7 +177,7 @@ def register_recurring_task(
178177
first_run_time: time | None = None,
179178
timeout: timedelta | None = timedelta(minutes=30),
180179
) -> typing.Callable[[TaskCallable[TaskParameters]], TaskCallable[TaskParameters]]:
181-
if not os.environ.get("RUN_BY_PROCESSOR"):
180+
if not settings.TASK_PROCESSOR_MODE:
182181
# Do not register recurring tasks if not invoked by task processor
183182
return lambda f: f
184183

tests/unit/task_processor/conftest.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,25 @@
22
import typing
33

44
import pytest
5+
from pytest_django.fixtures import SettingsWrapper
56

7+
from common.prometheus.utils import reload_metrics
68
from task_processor.task_registry import RegisteredTask
79

810

9-
@pytest.fixture
10-
def run_by_processor(monkeypatch: pytest.MonkeyPatch) -> None:
11-
monkeypatch.setenv("RUN_BY_PROCESSOR", "True")
11+
@pytest.fixture()
12+
def task_processor_mode(settings: SettingsWrapper) -> None:
13+
settings.TASK_PROCESSOR_MODE = True
14+
# The setting is supposed to be set before the metrics module is imported,
15+
# so reload it
16+
reload_metrics("task_processor.metrics")
17+
18+
19+
@pytest.fixture(autouse=True)
20+
def task_processor_mode_marked(request: pytest.FixtureRequest) -> None:
21+
for marker in request.node.iter_markers():
22+
if marker.name == "task_processor_mode":
23+
request.getfixturevalue("task_processor_mode")
1224

1325

1426
class GetTaskProcessorCaplog(typing.Protocol):

tests/unit/task_processor/test_unit_task_processor_decorators.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ def my_function(*args: typing.Any, **kwargs: typing.Any) -> None:
9999
)
100100

101101

102+
@pytest.mark.django_db
103+
@pytest.mark.task_processor_mode
102104
def test_register_recurring_task(
103105
mocker: MockerFixture,
104-
db: None,
105-
run_by_processor: None,
106106
) -> None:
107107
# Given
108108
mock = mocker.Mock()
@@ -128,10 +128,8 @@ def test_register_recurring_task(
128128
assert task.callable is mock
129129

130130

131-
def test_register_recurring_task_does_nothing_if_not_run_by_processor(
132-
mocker: MockerFixture,
133-
db: None,
134-
) -> None:
131+
@pytest.mark.django_db
132+
def test_register_recurring_task_does_nothing_if_not_run_by_processor() -> None:
135133
# Given
136134

137135
task_kwargs = {"first_arg": "foo", "second_arg": "bar"}
@@ -187,9 +185,8 @@ class NonSerializableObj:
187185
my_function.delay(args=(NonSerializableObj(),))
188186

189187

190-
def test_delay_returns_none_if_task_queue_is_full(
191-
settings: SettingsWrapper, db: None
192-
) -> None:
188+
@pytest.mark.django_db
189+
def test_delay_returns_none_if_task_queue_is_full(settings: SettingsWrapper) -> None:
193190
# Given
194191
settings.TASK_RUN_METHOD = TaskRunMethod.TASK_PROCESSOR
195192

@@ -209,9 +206,9 @@ def my_function(*args: typing.Any, **kwargs: typing.Any) -> None:
209206
assert task is None
210207

211208

209+
@pytest.mark.django_db
212210
def test_delay__expected_metrics(
213211
settings: SettingsWrapper,
214-
db: None,
215212
assert_metric: AssertMetricFixture,
216213
) -> None:
217214
# Given
@@ -232,7 +229,8 @@ def my_function(*args: typing.Any, **kwargs: typing.Any) -> None:
232229
)
233230

234231

235-
def test_can_create_task_with_priority(settings: SettingsWrapper, db: None) -> None:
232+
@pytest.mark.django_db
233+
def test_can_create_task_with_priority(settings: SettingsWrapper) -> None:
236234
# Given
237235
settings.TASK_RUN_METHOD = TaskRunMethod.TASK_PROCESSOR
238236

tests/unit/task_processor/test_unit_task_processor_health.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import pytest
12
from pytest_django.fixtures import SettingsWrapper
23
from pytest_mock import MockerFixture
34

@@ -25,8 +26,8 @@ def test_is_processor_healthy_returns_false_if_task_not_processed(
2526
assert result is False
2627

2728

29+
@pytest.mark.django_db
2830
def test_is_processor_healthy_returns_true_if_task_processed(
29-
db: None,
3031
settings: SettingsWrapper,
3132
) -> None:
3233
# Given

tests/unit/task_processor/test_unit_task_processor_monitoring.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
from datetime import timedelta
22

3+
import pytest
34
from django.utils import timezone
45

56
from task_processor.models import Task
67
from task_processor.monitoring import get_num_waiting_tasks
78

89

9-
def test_get_num_waiting_tasks(db: None) -> None:
10+
@pytest.mark.django_db
11+
def test_get_num_waiting_tasks() -> None:
1012
# Given
1113
now = timezone.now()
1214

0 commit comments

Comments
 (0)