Skip to content

Commit c273985

Browse files
authored
Merge pull request #23 from kraken-tech/transaction-callback-simulation-setting
Control after-commit calls in tests with a setting
2 parents 93c4785 + 7473c84 commit c273985

File tree

3 files changed

+21
-45
lines changed

3 files changed

+21
-45
lines changed

pytest.ini

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ addopts =
4545
# https://pytest-django.readthedocs.io/
4646
-p django
4747

48-
markers =
49-
# See Note [Running after-commit callbacks in tests]
50-
deprecated_ignore_after_commit_callbacks: require after-commit callbacks to be explicitly captured and called
51-
5248
# Ensure passing xfailed (aka "xpass") tests cause the test suite to fail.
5349
# https://docs.pytest.org/en/latest/skipping.html#strict-parameter
5450
xfail_strict = true

src/django_subatomic/db.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
from typing import NoReturn
1616

1717

18-
# See Note [Running after-commit callbacks in tests]
19-
_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS = True
20-
21-
2218
def dbs_with_open_transactions() -> frozenset[str]:
2319
"""
2420
Get the names of databases with open transactions.
@@ -224,7 +220,8 @@ def _execute_on_commit_callbacks_in_tests(using: str | None = None) -> Iterator[
224220
"""
225221
yield
226222
if (
227-
_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS # See Note [Running after-commit callbacks in tests]
223+
# See Note [Running after-commit callbacks in tests]
224+
getattr(settings, "SUBATOMIC_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS", True)
228225
and _innermost_atomic_block_wraps_testcase(using=using)
229226
):
230227
connection = django_transaction.get_connection(using)
@@ -335,6 +332,9 @@ class _UnexpectedDanglingTransaction(Exception):
335332
# To avoid that problem, we capture after-commit callbacks and execute them when we exit the
336333
# outermost `transaction` or `transaction_if_not_already` context. This emulates how the application
337334
# will behave when deployed and means that our tests are testing realistic application behaviour.
335+
#
336+
# To help projects migrate to this behaviour, it can be disabled with
337+
# the Django setting `SUBATOMIC_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS`.
338338

339339

340340
def run_after_commit(
@@ -368,8 +368,11 @@ def run_after_commit(
368368
if needs_transaction and not in_transaction(using=using):
369369
raise _MissingRequiredTransaction(database=using)
370370

371-
# See Note [Running after-commit callbacks in tests]
372-
if _RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS and only_in_testcase_transaction:
371+
if (
372+
# See Note [Running after-commit callbacks in tests]
373+
getattr(settings, "SUBATOMIC_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS", True)
374+
and only_in_testcase_transaction
375+
):
373376
callback()
374377
else:
375378
django_transaction.on_commit(callback, using=using)

tests/test_db.py

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import re
44
from typing import TYPE_CHECKING
5-
from unittest import mock
65

76
import pytest
87
from django import db as django_db
@@ -14,7 +13,7 @@
1413

1514
if TYPE_CHECKING:
1615
import contextlib
17-
from collections.abc import Callable, Generator
16+
from collections.abc import Callable
1817
from typing import Protocol
1918

2019
import pytest_django
@@ -60,28 +59,6 @@ def _parametrize_transaction_testcase(func: Callable[..., None]) -> MarkDecorato
6059
return parametrize(usefixtures(func)) # type: ignore[no-any-return]
6160

6261

63-
@pytest.fixture(autouse=True)
64-
def _prevent_after_commit_callbacks(
65-
request: pytest.FixtureRequest,
66-
) -> Generator[None, None, None]:
67-
"""
68-
Disable automatically running after-commit callbacks in marked tests.
69-
70-
If a test relies on after-commit callbacks never being called, it may be
71-
marked with `deprecated_ignore_after_commit_callbacks` to disable test simulation
72-
of how after-commit callbacks are naturally run after transactions.
73-
74-
TODO: Allow users of this library to do this in their own tests.
75-
76-
See Note [Running after-commit callbacks in tests]
77-
"""
78-
if "deprecated_ignore_after_commit_callbacks" in request.keywords:
79-
with mock.patch.object(db, "_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS", new=False):
80-
yield
81-
else:
82-
yield
83-
84-
8562
class Counter:
8663
def __init__(self) -> None:
8764
self.count = 0
@@ -463,25 +440,24 @@ def test_not_executed_if_rolled_back(self) -> None:
463440
assert counter.count == 0
464441

465442

466-
class TestRunAfterCommitDeprecatedTestBehaviour:
467-
@pytest.mark.deprecated_ignore_after_commit_callbacks
443+
class TestRunAfterCommitCallbacksSettingBehaviour:
468444
@override_settings(SUBATOMIC_AFTER_COMMIT_NEEDS_TRANSACTION=False)
469445
def test_does_not_execute_when_in_testcase_transaction_if_callbacks_disabled(
470446
self,
471447
) -> None:
472448
"""
473-
`run_after_commit` should not ignore testcase transactions when test marked with `deprecated_ignore_after_commit_callbacks`.
449+
`run_after_commit` should not ignore testcase transactions when SUBATOMIC_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS is False.
474450
475451
We have to disable `SUBATOMIC_AFTER_COMMIT_NEEDS_TRANSACTION`, because
476452
otherwise an error would be raised when trying to register the callback.
477453
"""
478454
counter = Counter()
479455

480-
db.run_after_commit(counter.increment)
456+
with override_settings(SUBATOMIC_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS=False):
457+
db.run_after_commit(counter.increment)
481458

482459
assert counter.count == 0
483460

484-
@pytest.mark.deprecated_ignore_after_commit_callbacks
485461
@pytest.mark.parametrize(
486462
"transaction_context",
487463
(
@@ -493,16 +469,17 @@ def test_does_not_execute_after_commit_if_decorated(
493469
self, transaction_context: DBContextManager
494470
) -> None:
495471
"""
496-
`run_after_commit` should not execute the callback when test marked with `deprecated_ignore_after_commit_callbacks`.
472+
`run_after_commit` should not execute the callback when SUBATOMIC_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS is False.
497473
"""
498474
counter = Counter()
499475

500-
with transaction_context():
501-
db.run_after_commit(counter.increment)
476+
with override_settings(SUBATOMIC_RUN_AFTER_COMMIT_CALLBACKS_IN_TESTS=False):
477+
with transaction_context():
478+
db.run_after_commit(counter.increment)
502479

503-
assert counter.count == 0
480+
assert counter.count == 0
504481

505-
assert counter.count == 0
482+
assert counter.count == 0
506483

507484

508485
class TestInTransaction:

0 commit comments

Comments
 (0)