-
Notifications
You must be signed in to change notification settings - Fork 347
Support Serialized Rollbacks for Databases #919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ Markers | |
``pytest.mark.django_db`` - request database access | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
.. py:function:: pytest.mark.django_db([transaction=False, reset_sequences=False]) | ||
.. py:function:: pytest.mark.django_db([transaction=False, reset_sequences=False, serialized_rollback=False]) | ||
|
||
This is used to mark a test function as requiring the database. It | ||
will ensure the database is set up correctly for the test. Each test | ||
|
@@ -54,6 +54,14 @@ Markers | |
effect. Please be aware that not all databases support this feature. | ||
For details see :py:attr:`django.test.TransactionTestCase.reset_sequences`. | ||
|
||
:type serialized_rollback: bool | ||
:param serialized_rollback: | ||
The ``serialized_rollback`` argument enables `rollback emulation`_. | ||
After a `django.test.TransactionTestCase`_ runs, the database is | ||
flushed, destroying data created in data migrations. This is the | ||
default behavior of Django. Setting ``serialized_rollback=True`` | ||
tells Django to restore that data. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to mention |
||
|
||
.. note:: | ||
|
||
If you want access to the Django database inside a *fixture*, this marker may | ||
|
@@ -69,7 +77,11 @@ Markers | |
Test classes that subclass :class:`django.test.TestCase` will have access to | ||
the database always to make them compatible with existing Django tests. | ||
Test classes that subclass Python's :class:`unittest.TestCase` need to have | ||
the marker applied in order to access the database. | ||
marker applied in order to access the database. | ||
|
||
.. _rollback emulation: https://docs.djangoproject.com/en/stable/topics/testing/overview/#rollback-emulation | ||
.. _django.test.TestCase: https://docs.djangoproject.com/en/dev/topics/testing/overview/#testcase | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. intersphinx references should be used when possible (see my example suggestion above,
|
||
.. _django.test.TransactionTestCase: https://docs.djangoproject.com/en/dev/topics/testing/overview/#transactiontestcase | ||
|
||
|
||
``pytest.mark.urls`` - override the urlconf | ||
|
@@ -314,6 +326,17 @@ use the :func:`pytest.mark.django_db` mark with ``transaction=True`` and | |
|
||
.. fixture:: live_server | ||
|
||
``django_db_serialized_rollback`` | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
When the ``transactional_db`` fixture is enabled, this fixture can be | ||
added to trigger `rollback emulation`_ and thus restores data created | ||
in data migrations after each transaction test. This is only required | ||
for fixtures which need to enforce this behavior. A test function | ||
would use ``pytest.mark.django_db(serialized_rollback=True)`` | ||
to request this behavior. | ||
|
||
|
||
``live_server`` | ||
~~~~~~~~~~~~~~~ | ||
|
||
|
@@ -323,6 +346,12 @@ or by requesting it's string value: ``str(live_server)``. You can | |
also directly concatenate a string to form a URL: ``live_server + | ||
'/foo'``. | ||
|
||
Since the live server and the tests run in different threads, they | ||
cannot share a database transaction. For this reason, ``live_server`` | ||
depends on the ``transactional_db`` fixture. If tests depend on data | ||
created in data migrations, you should add the ``serialized_rollback`` | ||
fixture. | ||
|
||
.. note:: Combining database access fixtures. | ||
|
||
When using multiple database fixtures together, only one of them is | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -16,6 +16,7 @@ | |||||||||||||||||||||
"db", | ||||||||||||||||||||||
"transactional_db", | ||||||||||||||||||||||
"django_db_reset_sequences", | ||||||||||||||||||||||
"django_db_serialized_rollback", | ||||||||||||||||||||||
"admin_user", | ||||||||||||||||||||||
"django_user_model", | ||||||||||||||||||||||
"django_username_field", | ||||||||||||||||||||||
|
@@ -124,7 +125,8 @@ def teardown_database(): | |||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
def _django_db_fixture_helper( | ||||||||||||||||||||||
request, django_db_blocker, transactional=False, reset_sequences=False | ||||||||||||||||||||||
request, django_db_blocker, transactional=False, reset_sequences=False, | ||||||||||||||||||||||
serialized_rollback=False | ||||||||||||||||||||||
): | ||||||||||||||||||||||
if is_django_unittest(request): | ||||||||||||||||||||||
return | ||||||||||||||||||||||
|
@@ -140,11 +142,16 @@ def _django_db_fixture_helper( | |||||||||||||||||||||
from django.test import TransactionTestCase as django_case | ||||||||||||||||||||||
|
||||||||||||||||||||||
if reset_sequences: | ||||||||||||||||||||||
|
||||||||||||||||||||||
class ResetSequenceTestCase(django_case): | ||||||||||||||||||||||
reset_sequences = True | ||||||||||||||||||||||
|
||||||||||||||||||||||
django_case = ResetSequenceTestCase | ||||||||||||||||||||||
|
||||||||||||||||||||||
if serialized_rollback: | ||||||||||||||||||||||
class SerializedRollbackTestCase(django_case): | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creating another subclass seems unnecessary. I will combine with the above (can call it |
||||||||||||||||||||||
serialized_rollback = True | ||||||||||||||||||||||
|
||||||||||||||||||||||
django_case = SerializedRollbackTestCase | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
from django.test import TestCase as django_case | ||||||||||||||||||||||
from django.db import transaction | ||||||||||||||||||||||
|
@@ -218,13 +225,16 @@ def db(request, django_db_setup, django_db_blocker): | |||||||||||||||||||||
""" | ||||||||||||||||||||||
if "django_db_reset_sequences" in request.fixturenames: | ||||||||||||||||||||||
request.getfixturevalue("django_db_reset_sequences") | ||||||||||||||||||||||
if "django_db_serialized_rollback" in request.fixturenames: | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to add it to the docstring above. |
||||||||||||||||||||||
request.getfixturevalue("django_db_serialized_rollback") | ||||||||||||||||||||||
if ( | ||||||||||||||||||||||
"transactional_db" in request.fixturenames | ||||||||||||||||||||||
or "live_server" in request.fixturenames | ||||||||||||||||||||||
): | ||||||||||||||||||||||
request.getfixturevalue("transactional_db") | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
_django_db_fixture_helper(request, django_db_blocker, transactional=False) | ||||||||||||||||||||||
_django_db_fixture_helper(request, django_db_blocker, transactional=False, | ||||||||||||||||||||||
serialized_rollback=False) | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
@pytest.fixture(scope="function") | ||||||||||||||||||||||
|
@@ -243,6 +253,8 @@ def transactional_db(request, django_db_setup, django_db_blocker): | |||||||||||||||||||||
""" | ||||||||||||||||||||||
if "django_db_reset_sequences" in request.fixturenames: | ||||||||||||||||||||||
request.getfixturevalue("django_db_reset_sequences") | ||||||||||||||||||||||
if "django_db_serialized_rollback" in request.fixturenames: | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to add |
||||||||||||||||||||||
request.getfixturevalue("django_db_serialized_rollback") | ||||||||||||||||||||||
_django_db_fixture_helper(request, django_db_blocker, transactional=True) | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
|
@@ -264,6 +276,20 @@ def django_db_reset_sequences(request, django_db_setup, django_db_blocker): | |||||||||||||||||||||
) | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
@pytest.fixture(scope="function") | ||||||||||||||||||||||
def django_db_serialized_rollback(request, django_db_setup, django_db_blocker): | ||||||||||||||||||||||
"""Enable serialized rollback after transaction test cases | ||||||||||||||||||||||
|
||||||||||||||||||||||
This fixture only has an effect when the ``transactional_db`` | ||||||||||||||||||||||
fixture is active, which happen as a side-effect of requesting | ||||||||||||||||||||||
``live_server``. | ||||||||||||||||||||||
|
||||||||||||||||||||||
Comment on lines
+281
to
+286
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
""" | ||||||||||||||||||||||
_django_db_fixture_helper( | ||||||||||||||||||||||
request, django_db_blocker, transactional=True, serialized_rollback=True | ||||||||||||||||||||||
) | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
@pytest.fixture() | ||||||||||||||||||||||
def client(): | ||||||||||||||||||||||
"""A Django test client instance.""" | ||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.