Fixed DatabaseFeatures.uses_savepoints/can_release_savepoints and related tests with MyISAM storage engine.

This commit is contained in:
Mariusz Felisiak 2022-04-14 09:53:31 +02:00
parent e12670016b
commit 331a460f8f
6 changed files with 14 additions and 5 deletions

View File

@ -305,6 +305,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
""" """
return self._mysql_storage_engine != "MyISAM" return self._mysql_storage_engine != "MyISAM"
uses_savepoints = property(operator.attrgetter("supports_transactions"))
can_release_savepoints = property(operator.attrgetter("supports_transactions"))
@cached_property @cached_property
def ignores_table_name_case(self): def ignores_table_name_case(self):
return self.connection.mysql_server_data["lower_case_table_names"] return self.connection.mysql_server_data["lower_case_table_names"]

View File

@ -30,6 +30,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core import mail from django.core import mail
from django.core.checks import Error from django.core.checks import Error
from django.core.files import temp as tempfile from django.core.files import temp as tempfile
from django.db import connection
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.test import ( from django.test import (
@ -7022,7 +7023,8 @@ class UserAdminTest(TestCase):
# Don't depend on a warm cache, see #17377. # Don't depend on a warm cache, see #17377.
ContentType.objects.clear_cache() ContentType.objects.clear_cache()
with self.assertNumQueries(10): expected_num_queries = 10 if connection.features.uses_savepoints else 8
with self.assertNumQueries(expected_num_queries):
response = self.client.get(reverse("admin:auth_user_change", args=(u.pk,))) response = self.client.get(reverse("admin:auth_user_change", args=(u.pk,)))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@ -7069,7 +7071,8 @@ class GroupAdminTest(TestCase):
# Ensure no queries are skipped due to cached content type for Group. # Ensure no queries are skipped due to cached content type for Group.
ContentType.objects.clear_cache() ContentType.objects.clear_cache()
with self.assertNumQueries(8): expected_num_queries = 8 if connection.features.uses_savepoints else 6
with self.assertNumQueries(expected_num_queries):
response = self.client.get(reverse("admin:auth_group_change", args=(g.pk,))) response = self.client.get(reverse("admin:auth_group_change", args=(g.pk,)))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)

View File

@ -11,6 +11,7 @@ class TestFeatures(TestCase):
""" """
All storage engines except MyISAM support transactions. All storage engines except MyISAM support transactions.
""" """
del connection.features.supports_transactions
with mock.patch( with mock.patch(
"django.db.connection.features._mysql_storage_engine", "InnoDB" "django.db.connection.features._mysql_storage_engine", "InnoDB"
): ):

View File

@ -291,7 +291,7 @@ class SelectForUpdateTests(TransactionTestCase):
qs = Person.objects.select_for_update(of=("self", "born")) qs = Person.objects.select_for_update(of=("self", "born"))
self.assertIs(qs.exists(), True) self.assertIs(qs.exists(), True)
@skipUnlessDBFeature("has_select_for_update_nowait") @skipUnlessDBFeature("has_select_for_update_nowait", "supports_transactions")
def test_nowait_raises_error_on_block(self): def test_nowait_raises_error_on_block(self):
""" """
If nowait is specified, we expect an error to be raised rather If nowait is specified, we expect an error to be raised rather
@ -312,7 +312,7 @@ class SelectForUpdateTests(TransactionTestCase):
self.end_blocking_transaction() self.end_blocking_transaction()
self.assertIsInstance(status[-1], DatabaseError) self.assertIsInstance(status[-1], DatabaseError)
@skipUnlessDBFeature("has_select_for_update_skip_locked") @skipUnlessDBFeature("has_select_for_update_skip_locked", "supports_transactions")
def test_skip_locked_skips_locked_rows(self): def test_skip_locked_skips_locked_rows(self):
""" """
If skip_locked is specified, the locked row is skipped resulting in If skip_locked is specified, the locked row is skipped resulting in
@ -599,7 +599,7 @@ class SelectForUpdateTests(TransactionTestCase):
p = Person.objects.get(pk=self.person.pk) p = Person.objects.get(pk=self.person.pk)
self.assertEqual("Fred", p.name) self.assertEqual("Fred", p.name)
@skipUnlessDBFeature("has_select_for_update") @skipUnlessDBFeature("has_select_for_update", "supports_transactions")
def test_raw_lock_not_available(self): def test_raw_lock_not_available(self):
""" """
Running a raw query which can't obtain a FOR UPDATE lock raises Running a raw query which can't obtain a FOR UPDATE lock raises

View File

@ -8,6 +8,7 @@ class ForcedError(Exception):
pass pass
@skipUnlessDBFeature("supports_transactions")
class TestConnectionOnCommit(TransactionTestCase): class TestConnectionOnCommit(TransactionTestCase):
""" """
Tests for transaction.on_commit(). Tests for transaction.on_commit().

View File

@ -370,6 +370,7 @@ class AtomicErrorsTests(TransactionTestCase):
self.assertEqual(Reporter.objects.count(), 0) self.assertEqual(Reporter.objects.count(), 0)
@skipUnlessDBFeature("uses_savepoints")
@skipUnless(connection.vendor == "mysql", "MySQL-specific behaviors") @skipUnless(connection.vendor == "mysql", "MySQL-specific behaviors")
class AtomicMySQLTests(TransactionTestCase): class AtomicMySQLTests(TransactionTestCase):