mirror of
https://github.com/Hopiu/django-cachalot.git
synced 2026-03-16 21:30:23 +00:00
Correct problems with tests (#234)
This commit is contained in:
parent
b2d9de2997
commit
27eaaa57cc
9 changed files with 115 additions and 87 deletions
|
|
@ -4,14 +4,20 @@ What’s new in django-cachalot?
|
||||||
2.6.0
|
2.6.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
- Dropped Django 2.2 and 4.0 support. Added Django 4.2 and Python 3.11 support. Added psycopg support (#229)
|
- Dropped Django 2.2 and 4.0 support
|
||||||
|
- Added Django 4.2 and Python 3.11 support
|
||||||
|
- Added psycopg support (#229)
|
||||||
|
- Updated tests to account for the `BEGIN` and `COMMIT` query changes in Django 4.2
|
||||||
|
- Standardized django version comparisons in tests
|
||||||
|
|
||||||
2.5.3
|
2.5.3
|
||||||
-----
|
-----
|
||||||
|
|
||||||
- Verify get_meta isn't none before requesting db_table (#225 #226)
|
- Verify get_meta isn't none before requesting db_table (#225 #226)
|
||||||
|
|
||||||
2.5.2
|
2.5.2
|
||||||
-----
|
-----
|
||||||
|
|
||||||
- Added Django 4.1 support (#217)
|
- Added Django 4.1 support (#217)
|
||||||
|
|
||||||
2.5.1
|
2.5.1
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ class PostgresModel(Model):
|
||||||
null=True, blank=True)
|
null=True, blank=True)
|
||||||
|
|
||||||
hstore = HStoreField(null=True, blank=True)
|
hstore = HStoreField(null=True, blank=True)
|
||||||
if DJANGO_VERSION[0] < 4:
|
if DJANGO_VERSION < (4, 0):
|
||||||
from django.contrib.postgres.fields import JSONField
|
from django.contrib.postgres.fields import JSONField
|
||||||
json = JSONField(null=True, blank=True)
|
json = JSONField(null=True, blank=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
from unittest import skipIf
|
from unittest import skipIf
|
||||||
|
|
||||||
from django import VERSION as DJANGO_VERSION
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import DEFAULT_DB_ALIAS, connections, transaction
|
from django.db import DEFAULT_DB_ALIAS, connections, transaction
|
||||||
from django.test import TransactionTestCase
|
from django.test import TransactionTestCase
|
||||||
|
|
@ -27,24 +26,6 @@ class MultiDatabaseTestCase(TransactionTestCase):
|
||||||
# will execute an extra SQL request below.
|
# will execute an extra SQL request below.
|
||||||
connection2.cursor()
|
connection2.cursor()
|
||||||
|
|
||||||
def is_django_21_below_and_sqlite2(self):
|
|
||||||
"""
|
|
||||||
Note: See test_utils.py with this function name
|
|
||||||
Checks if Django 2.1 or below and SQLite2
|
|
||||||
"""
|
|
||||||
django_version = DJANGO_VERSION
|
|
||||||
if not self.is_sqlite2:
|
|
||||||
# Immediately know if SQLite
|
|
||||||
return False
|
|
||||||
if django_version[0] < 2:
|
|
||||||
# Takes Django 0 and 1 out of the picture
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
if django_version[0] == 2 and django_version[1] < 2:
|
|
||||||
# Takes Django 2.0-2.1 out
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def test_read(self):
|
def test_read(self):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
|
|
@ -66,8 +47,7 @@ class MultiDatabaseTestCase(TransactionTestCase):
|
||||||
data1 = list(Test.objects.using(self.db_alias2))
|
data1 = list(Test.objects.using(self.db_alias2))
|
||||||
self.assertListEqual(data1, [])
|
self.assertListEqual(data1, [])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_django_21_below_and_sqlite2() else 1,
|
with self.assertNumQueries(1, using=self.db_alias2):
|
||||||
using=self.db_alias2):
|
|
||||||
t3 = Test.objects.using(self.db_alias2).create(name='test3')
|
t3 = Test.objects.using(self.db_alias2).create(name='test3')
|
||||||
|
|
||||||
with self.assertNumQueries(1, using=self.db_alias2):
|
with self.assertNumQueries(1, using=self.db_alias2):
|
||||||
|
|
@ -82,8 +62,7 @@ class MultiDatabaseTestCase(TransactionTestCase):
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
self.assertListEqual(data1, [self.t1, self.t2])
|
self.assertListEqual(data1, [self.t1, self.t2])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_django_21_below_and_sqlite2() else 1,
|
with self.assertNumQueries(1, using=self.db_alias2):
|
||||||
using=self.db_alias2):
|
|
||||||
Test.objects.using(self.db_alias2).create(name='test3')
|
Test.objects.using(self.db_alias2).create(name='test3')
|
||||||
|
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from unittest import skipIf
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django import VERSION as django_version
|
from django import VERSION as DJANGO_VERSION
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import Group, Permission, User
|
from django.contrib.auth.models import Group, Permission, User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
@ -353,7 +353,7 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
@all_final_sql_checks
|
@all_final_sql_checks
|
||||||
def test_subquery(self):
|
def test_subquery(self):
|
||||||
additional_tables = []
|
additional_tables = []
|
||||||
if django_version[0] == 4 and django_version[1] < 1 and settings.CACHALOT_FINAL_SQL_CHECK:
|
if DJANGO_VERSION >= (4, 0) and DJANGO_VERSION < (4, 1) and settings.CACHALOT_FINAL_SQL_CHECK:
|
||||||
# with Django 4.0 comes some query optimalizations that do selects little differently.
|
# with Django 4.0 comes some query optimalizations that do selects little differently.
|
||||||
additional_tables.append('django_content_type')
|
additional_tables.append('django_content_type')
|
||||||
qs = Test.objects.filter(owner__in=User.objects.all())
|
qs = Test.objects.filter(owner__in=User.objects.all())
|
||||||
|
|
@ -694,7 +694,7 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assert_query_cached(qs)
|
self.assert_query_cached(qs)
|
||||||
|
|
||||||
with self.assertRaisesMessage(
|
with self.assertRaisesMessage(
|
||||||
AssertionError if django_version[0] < 4 else TypeError,
|
AssertionError if DJANGO_VERSION < (4, 0) else TypeError,
|
||||||
'Cannot combine queries on two different base models.'
|
'Cannot combine queries on two different base models.'
|
||||||
):
|
):
|
||||||
Test.objects.all() | Permission.objects.all()
|
Test.objects.all() | Permission.objects.all()
|
||||||
|
|
@ -739,7 +739,7 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assert_query_cached(qs)
|
self.assert_query_cached(qs)
|
||||||
|
|
||||||
with self.assertRaisesMessage(
|
with self.assertRaisesMessage(
|
||||||
AssertionError if django_version[0] < 4 else TypeError,
|
AssertionError if DJANGO_VERSION < (4, 0) else TypeError,
|
||||||
'Cannot combine queries on two different base models.'):
|
'Cannot combine queries on two different base models.'):
|
||||||
Test.objects.all() & Permission.objects.all()
|
Test.objects.all() & Permission.objects.all()
|
||||||
|
|
||||||
|
|
@ -816,21 +816,21 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
with self.assertRaises(TransactionManagementError):
|
with self.assertRaises(TransactionManagementError):
|
||||||
list(Test.objects.select_for_update())
|
list(Test.objects.select_for_update())
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data1 = list(Test.objects.select_for_update())
|
data1 = list(Test.objects.select_for_update())
|
||||||
self.assertListEqual(data1, [self.t1, self.t2])
|
self.assertListEqual(data1, [self.t1, self.t2])
|
||||||
self.assertListEqual([t.name for t in data1],
|
self.assertListEqual([t.name for t in data1],
|
||||||
['test1', 'test2'])
|
['test1', 'test2'])
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data2 = list(Test.objects.select_for_update())
|
data2 = list(Test.objects.select_for_update())
|
||||||
self.assertListEqual(data2, [self.t1, self.t2])
|
self.assertListEqual(data2, [self.t1, self.t2])
|
||||||
self.assertListEqual([t.name for t in data2],
|
self.assertListEqual([t.name for t in data2],
|
||||||
['test1', 'test2'])
|
['test1', 'test2'])
|
||||||
|
|
||||||
with self.assertNumQueries(2):
|
with self.assertNumQueries(4 if DJANGO_VERSION >= (4, 2) else 2):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data3 = list(Test.objects.select_for_update())
|
data3 = list(Test.objects.select_for_update())
|
||||||
data4 = list(Test.objects.select_for_update())
|
data4 = list(Test.objects.select_for_update())
|
||||||
|
|
@ -896,7 +896,9 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assert_query_cached(qs, [self.t2, self.t1])
|
self.assert_query_cached(qs, [self.t2, self.t1])
|
||||||
|
|
||||||
def test_table_inheritance(self):
|
def test_table_inheritance(self):
|
||||||
with self.assertNumQueries(3 if self.is_sqlite else 2):
|
with self.assertNumQueries(
|
||||||
|
3 if self.is_sqlite else (4 if DJANGO_VERSION >= (4, 2) else 2)
|
||||||
|
):
|
||||||
t_child = TestChild.objects.create(name='test_child')
|
t_child = TestChild.objects.create(name='test_child')
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
|
|
@ -911,15 +913,10 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
expected = (r'\d+ 0 0 SCAN cachalot_test\n'
|
expected = (r'\d+ 0 0 SCAN cachalot_test\n'
|
||||||
r'\d+ 0 0 USE TEMP B-TREE FOR ORDER BY')
|
r'\d+ 0 0 USE TEMP B-TREE FOR ORDER BY')
|
||||||
elif self.is_mysql:
|
elif self.is_mysql:
|
||||||
if self.django_version < (3, 1):
|
expected = (
|
||||||
expected = (
|
r'-> Sort row IDs: cachalot_test.`name` \(cost=[\d\.]+ rows=\d\)\n '
|
||||||
r'1 SIMPLE cachalot_test '
|
r'-> Table scan on cachalot_test \(cost=[\d\.]+ rows=\d\)\n'
|
||||||
r'(?:None )?ALL None None None None 2 100\.0 Using filesort')
|
)
|
||||||
else:
|
|
||||||
expected = (
|
|
||||||
r'-> Sort row IDs: cachalot_test.`name` \(cost=[\d\.]+ rows=\d\)\n '
|
|
||||||
r'-> Table scan on cachalot_test \(cost=[\d\.]+ rows=\d\)\n'
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
explain_kwargs.update(
|
explain_kwargs.update(
|
||||||
analyze=True,
|
analyze=True,
|
||||||
|
|
@ -935,9 +932,7 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
r'Planning Time: [\d\.]+ ms\n'
|
r'Planning Time: [\d\.]+ ms\n'
|
||||||
r'Execution Time: [\d\.]+ ms$') % (operation_detail,
|
r'Execution Time: [\d\.]+ ms$') % (operation_detail,
|
||||||
operation_detail)
|
operation_detail)
|
||||||
with self.assertNumQueries(
|
with self.assertNumQueries(1):
|
||||||
2 if self.is_mysql and django_version[0] < 3
|
|
||||||
else 1):
|
|
||||||
explanation1 = Test.objects.explain(**explain_kwargs)
|
explanation1 = Test.objects.explain(**explain_kwargs)
|
||||||
self.assertRegex(explanation1, expected)
|
self.assertRegex(explanation1, expected)
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
from django import VERSION as DJANGO_VERSION
|
|
||||||
from django.core.management.color import no_style
|
from django.core.management.color import no_style
|
||||||
from django.db import connection, transaction
|
from django.db import connection, transaction
|
||||||
|
|
||||||
|
|
@ -11,7 +10,6 @@ class TestUtilsMixin:
|
||||||
self.is_sqlite = connection.vendor == 'sqlite'
|
self.is_sqlite = connection.vendor == 'sqlite'
|
||||||
self.is_mysql = connection.vendor == 'mysql'
|
self.is_mysql = connection.vendor == 'mysql'
|
||||||
self.is_postgresql = connection.vendor == 'postgresql'
|
self.is_postgresql = connection.vendor == 'postgresql'
|
||||||
self.django_version = DJANGO_VERSION
|
|
||||||
self.force_reopen_connection()
|
self.force_reopen_connection()
|
||||||
|
|
||||||
# TODO: Remove this workaround when this issue is fixed:
|
# TODO: Remove this workaround when this issue is fixed:
|
||||||
|
|
@ -19,8 +17,6 @@ class TestUtilsMixin:
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
if connection.vendor == 'postgresql':
|
if connection.vendor == 'postgresql':
|
||||||
flush_args = [no_style(), (PostgresModel._meta.db_table,),]
|
flush_args = [no_style(), (PostgresModel._meta.db_table,),]
|
||||||
if float(".".join(map(str, DJANGO_VERSION[:2]))) < 3.1:
|
|
||||||
flush_args.append(())
|
|
||||||
flush_sql_list = connection.ops.sql_flush(*flush_args)
|
flush_sql_list = connection.ops.sql_flush(*flush_args)
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
for sql in flush_sql_list:
|
for sql in flush_sql_list:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
|
from django import VERSION as DJANGO_VERSION
|
||||||
from django.db import connection, transaction
|
from django.db import connection, transaction
|
||||||
from django.test import TransactionTestCase, skipUnlessDBFeature
|
from django.test import TransactionTestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ class ThreadSafetyTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertEqual(t2, t)
|
self.assertEqual(t2, t)
|
||||||
|
|
||||||
def test_concurrent_caching_during_atomic(self):
|
def test_concurrent_caching_during_atomic(self):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t1 = TestThread().start_and_join()
|
t1 = TestThread().start_and_join()
|
||||||
t = Test.objects.create(name='test')
|
t = Test.objects.create(name='test')
|
||||||
|
|
@ -45,7 +46,7 @@ class ThreadSafetyTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
def test_concurrent_caching_before_and_during_atomic_1(self):
|
def test_concurrent_caching_before_and_during_atomic_1(self):
|
||||||
t1 = TestThread().start_and_join()
|
t1 = TestThread().start_and_join()
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t2 = TestThread().start_and_join()
|
t2 = TestThread().start_and_join()
|
||||||
t = Test.objects.create(name='test')
|
t = Test.objects.create(name='test')
|
||||||
|
|
@ -60,7 +61,7 @@ class ThreadSafetyTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
def test_concurrent_caching_before_and_during_atomic_2(self):
|
def test_concurrent_caching_before_and_during_atomic_2(self):
|
||||||
t1 = TestThread().start_and_join()
|
t1 = TestThread().start_and_join()
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t = Test.objects.create(name='test')
|
t = Test.objects.create(name='test')
|
||||||
t2 = TestThread().start_and_join()
|
t2 = TestThread().start_and_join()
|
||||||
|
|
@ -73,7 +74,7 @@ class ThreadSafetyTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertEqual(data, t)
|
self.assertEqual(data, t)
|
||||||
|
|
||||||
def test_concurrent_caching_during_and_after_atomic_1(self):
|
def test_concurrent_caching_during_and_after_atomic_1(self):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t1 = TestThread().start_and_join()
|
t1 = TestThread().start_and_join()
|
||||||
t = Test.objects.create(name='test')
|
t = Test.objects.create(name='test')
|
||||||
|
|
@ -88,7 +89,7 @@ class ThreadSafetyTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertEqual(data, t)
|
self.assertEqual(data, t)
|
||||||
|
|
||||||
def test_concurrent_caching_during_and_after_atomic_2(self):
|
def test_concurrent_caching_during_and_after_atomic_2(self):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t = Test.objects.create(name='test')
|
t = Test.objects.create(name='test')
|
||||||
t1 = TestThread().start_and_join()
|
t1 = TestThread().start_and_join()
|
||||||
|
|
@ -103,7 +104,7 @@ class ThreadSafetyTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertEqual(data, t)
|
self.assertEqual(data, t)
|
||||||
|
|
||||||
def test_concurrent_caching_during_and_after_atomic_3(self):
|
def test_concurrent_caching_during_and_after_atomic_3(self):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t1 = TestThread().start_and_join()
|
t1 = TestThread().start_and_join()
|
||||||
t = Test.objects.create(name='test')
|
t = Test.objects.create(name='test')
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
from cachalot.transaction import AtomicCache
|
from cachalot.transaction import AtomicCache
|
||||||
|
|
||||||
|
from django import VERSION as DJANGO_VERSION
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db import transaction, connection, IntegrityError
|
from django.db import transaction, connection, IntegrityError
|
||||||
|
|
@ -10,7 +12,9 @@ from .test_utils import TestUtilsMixin
|
||||||
|
|
||||||
class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
def test_successful_read_atomic(self):
|
def test_successful_read_atomic(self):
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
self.assertListEqual(data1, [])
|
self.assertListEqual(data1, [])
|
||||||
|
|
@ -20,7 +24,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertListEqual(data2, [])
|
self.assertListEqual(data2, [])
|
||||||
|
|
||||||
def test_unsuccessful_read_atomic(self):
|
def test_unsuccessful_read_atomic(self):
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
|
|
@ -38,21 +44,27 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
self.assertListEqual(data1, [])
|
self.assertListEqual(data1, [])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t1 = Test.objects.create(name='test1')
|
t1 = Test.objects.create(name='test1')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
data2 = list(Test.objects.all())
|
data2 = list(Test.objects.all())
|
||||||
self.assertListEqual(data2, [t1])
|
self.assertListEqual(data2, [t1])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t2 = Test.objects.create(name='test2')
|
t2 = Test.objects.create(name='test2')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
data3 = list(Test.objects.all())
|
data3 = list(Test.objects.all())
|
||||||
self.assertListEqual(data3, [t1, t2])
|
self.assertListEqual(data3, [t1, t2])
|
||||||
|
|
||||||
with self.assertNumQueries(4 if self.is_sqlite else 3):
|
with self.assertNumQueries(
|
||||||
|
4 if self.is_sqlite else (5 if DJANGO_VERSION >= (4, 2) else 3)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data4 = list(Test.objects.all())
|
data4 = list(Test.objects.all())
|
||||||
t3 = Test.objects.create(name='test3')
|
t3 = Test.objects.create(name='test3')
|
||||||
|
|
@ -67,7 +79,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
self.assertListEqual(data1, [])
|
self.assertListEqual(data1, [])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
Test.objects.create(name='test')
|
Test.objects.create(name='test')
|
||||||
|
|
@ -82,7 +96,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
Test.objects.get(name='test')
|
Test.objects.get(name='test')
|
||||||
|
|
||||||
def test_cache_inside_atomic(self):
|
def test_cache_inside_atomic(self):
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
data2 = list(Test.objects.all())
|
data2 = list(Test.objects.all())
|
||||||
|
|
@ -90,7 +106,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertListEqual(data2, [])
|
self.assertListEqual(data2, [])
|
||||||
|
|
||||||
def test_invalidation_inside_atomic(self):
|
def test_invalidation_inside_atomic(self):
|
||||||
with self.assertNumQueries(4 if self.is_sqlite else 3):
|
with self.assertNumQueries(
|
||||||
|
4 if self.is_sqlite else (5 if DJANGO_VERSION >= (4, 2) else 3)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
t = Test.objects.create(name='test')
|
t = Test.objects.create(name='test')
|
||||||
|
|
@ -99,7 +117,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertListEqual(data2, [t])
|
self.assertListEqual(data2, [t])
|
||||||
|
|
||||||
def test_successful_nested_read_atomic(self):
|
def test_successful_nested_read_atomic(self):
|
||||||
with self.assertNumQueries(7 if self.is_sqlite else 6):
|
with self.assertNumQueries(
|
||||||
|
7 if self.is_sqlite else (8 if DJANGO_VERSION >= (4, 2) else 6)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
list(Test.objects.all())
|
list(Test.objects.all())
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
|
@ -114,7 +134,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
list(User.objects.all())
|
list(User.objects.all())
|
||||||
|
|
||||||
def test_unsuccessful_nested_read_atomic(self):
|
def test_unsuccessful_nested_read_atomic(self):
|
||||||
with self.assertNumQueries(6 if self.is_sqlite else 5):
|
with self.assertNumQueries(
|
||||||
|
6 if self.is_sqlite else (7 if DJANGO_VERSION >= (4, 2) else 5)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
|
@ -127,7 +149,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
list(Test.objects.all())
|
list(Test.objects.all())
|
||||||
|
|
||||||
def test_successful_nested_write_atomic(self):
|
def test_successful_nested_write_atomic(self):
|
||||||
with self.assertNumQueries(13 if self.is_sqlite else 12):
|
with self.assertNumQueries(
|
||||||
|
13 if self.is_sqlite else (14 if DJANGO_VERSION >= (4, 2) else 12)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t1 = Test.objects.create(name='test1')
|
t1 = Test.objects.create(name='test1')
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
|
@ -144,7 +168,9 @@ class AtomicTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertListEqual(data3, [t1, t2, t3, t4])
|
self.assertListEqual(data3, [t1, t2, t3, t4])
|
||||||
|
|
||||||
def test_unsuccessful_nested_write_atomic(self):
|
def test_unsuccessful_nested_write_atomic(self):
|
||||||
with self.assertNumQueries(16 if self.is_sqlite else 15):
|
with self.assertNumQueries(
|
||||||
|
16 if self.is_sqlite else (17 if DJANGO_VERSION >= (4, 2) else 15)
|
||||||
|
):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
t1 = Test.objects.create(name='test1')
|
t1 = Test.objects.create(name='test1')
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
from unittest import skipIf, skipUnless
|
from unittest import skipIf, skipUnless
|
||||||
|
|
||||||
from django import VERSION as DJANGO_VERSION
|
from django import VERSION as DJANGO_VERSION
|
||||||
|
|
@ -56,7 +58,9 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
self.assertListEqual(data1, [])
|
self.assertListEqual(data1, [])
|
||||||
|
|
||||||
with self.assertNumQueries(3 if self.is_sqlite else 2):
|
with self.assertNumQueries(
|
||||||
|
3 if self.is_sqlite else (4 if DJANGO_VERSION >= (4, 2) else 2)
|
||||||
|
):
|
||||||
t, created = Test.objects.get_or_create(name='test')
|
t, created = Test.objects.get_or_create(name='test')
|
||||||
self.assertTrue(created)
|
self.assertTrue(created)
|
||||||
|
|
||||||
|
|
@ -78,14 +82,18 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
self.assertListEqual(list(Test.objects.all()), [])
|
self.assertListEqual(list(Test.objects.all()), [])
|
||||||
|
|
||||||
with self.assertNumQueries(5 if self.is_sqlite else 4):
|
with self.assertNumQueries(
|
||||||
|
5 if self.is_sqlite else (6 if DJANGO_VERSION >= (4, 2) else 4)
|
||||||
|
):
|
||||||
t, created = Test.objects.update_or_create(
|
t, created = Test.objects.update_or_create(
|
||||||
name='test', defaults={'public': True})
|
name='test', defaults={'public': True})
|
||||||
self.assertTrue(created)
|
self.assertTrue(created)
|
||||||
self.assertEqual(t.name, 'test')
|
self.assertEqual(t.name, 'test')
|
||||||
self.assertEqual(t.public, True)
|
self.assertEqual(t.public, True)
|
||||||
|
|
||||||
with self.assertNumQueries(3 if self.is_sqlite else 2):
|
with self.assertNumQueries(
|
||||||
|
3 if self.is_sqlite else (4 if DJANGO_VERSION >= (4, 2) else 2)
|
||||||
|
):
|
||||||
t, created = Test.objects.update_or_create(
|
t, created = Test.objects.update_or_create(
|
||||||
name='test', defaults={'public': False})
|
name='test', defaults={'public': False})
|
||||||
self.assertFalse(created)
|
self.assertFalse(created)
|
||||||
|
|
@ -94,7 +102,9 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
|
|
||||||
# The number of SQL queries doesn’t decrease because update_or_create
|
# The number of SQL queries doesn’t decrease because update_or_create
|
||||||
# always calls an UPDATE, even when data wasn’t changed.
|
# always calls an UPDATE, even when data wasn’t changed.
|
||||||
with self.assertNumQueries(3 if self.is_sqlite else 2):
|
with self.assertNumQueries(
|
||||||
|
3 if self.is_sqlite else (4 if DJANGO_VERSION >= (4, 2) else 2)
|
||||||
|
):
|
||||||
t, created = Test.objects.update_or_create(
|
t, created = Test.objects.update_or_create(
|
||||||
name='test', defaults={'public': False})
|
name='test', defaults={'public': False})
|
||||||
self.assertFalse(created)
|
self.assertFalse(created)
|
||||||
|
|
@ -109,17 +119,21 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
data1 = list(Test.objects.all())
|
data1 = list(Test.objects.all())
|
||||||
self.assertListEqual(data1, [])
|
self.assertListEqual(data1, [])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
unsaved_tests = [Test(name='test%02d' % i) for i in range(1, 11)]
|
unsaved_tests = [Test(name='test%02d' % i) for i in range(1, 11)]
|
||||||
Test.objects.bulk_create(unsaved_tests)
|
Test.objects.bulk_create(unsaved_tests)
|
||||||
self.assertEqual(Test.objects.count(), 10)
|
self.assertEqual(Test.objects.count(), 10)
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
unsaved_tests = [Test(name='test%02d' % i) for i in range(1, 11)]
|
unsaved_tests = [Test(name='test%02d' % i) for i in range(1, 11)]
|
||||||
Test.objects.bulk_create(unsaved_tests)
|
Test.objects.bulk_create(unsaved_tests)
|
||||||
self.assertEqual(Test.objects.count(), 20)
|
self.assertEqual(Test.objects.count(), 20)
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else else 1):
|
||||||
data2 = list(Test.objects.all())
|
data2 = list(Test.objects.all())
|
||||||
self.assertEqual(len(data2), 20)
|
self.assertEqual(len(data2), 20)
|
||||||
self.assertListEqual([t.name for t in data2],
|
self.assertListEqual([t.name for t in data2],
|
||||||
|
|
@ -160,12 +174,16 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertListEqual(data1, [t1.name, t2.name])
|
self.assertListEqual(data1, [t1.name, t2.name])
|
||||||
self.assertListEqual(data2, [t1.name])
|
self.assertListEqual(data2, [t1.name])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
Test.objects.bulk_create([Test(name='test%s' % i)
|
Test.objects.bulk_create([Test(name='test%s' % i)
|
||||||
for i in range(2, 11)])
|
for i in range(2, 11)])
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
self.assertEqual(Test.objects.count(), 10)
|
self.assertEqual(Test.objects.count(), 10)
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
Test.objects.all().delete()
|
Test.objects.all().delete()
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
self.assertEqual(Test.objects.count(), 0)
|
self.assertEqual(Test.objects.count(), 0)
|
||||||
|
|
@ -360,7 +378,9 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertListEqual(data4, [user1, user2])
|
self.assertListEqual(data4, [user1, user2])
|
||||||
self.assertListEqual([u.n for u in data4], [1, 0])
|
self.assertListEqual([u.n for u in data4], [1, 0])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
Test.objects.bulk_create([
|
Test.objects.bulk_create([
|
||||||
Test(name='test3', owner=user1),
|
Test(name='test3', owner=user1),
|
||||||
Test(name='test4', owner=user2),
|
Test(name='test4', owner=user2),
|
||||||
|
|
@ -588,7 +608,9 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
data2 = list(Test.objects.select_related('owner'))
|
data2 = list(Test.objects.select_related('owner'))
|
||||||
self.assertListEqual(data2, [])
|
self.assertListEqual(data2, [])
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
Test.objects.bulk_create([
|
Test.objects.bulk_create([
|
||||||
Test(name='test1', owner=u1),
|
Test(name='test1', owner=u1),
|
||||||
Test(name='test2', owner=u2),
|
Test(name='test2', owner=u2),
|
||||||
|
|
@ -602,7 +624,9 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertEqual(data3[2].owner, u2)
|
self.assertEqual(data3[2].owner, u2)
|
||||||
self.assertEqual(data3[3].owner, u1)
|
self.assertEqual(data3[3].owner, u1)
|
||||||
|
|
||||||
with self.assertNumQueries(2 if self.is_sqlite else 1):
|
with self.assertNumQueries(
|
||||||
|
2 if self.is_sqlite else (3 if DJANGO_VERSION >= (4, 2) else 1)
|
||||||
|
):
|
||||||
Test.objects.filter(name__in=['test1', 'test2']).delete()
|
Test.objects.filter(name__in=['test1', 'test2']).delete()
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
data4 = list(Test.objects.select_related('owner'))
|
data4 = list(Test.objects.select_related('owner'))
|
||||||
|
|
@ -635,9 +659,9 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
self.assertListEqual(list(data3[0].owner.groups.all()), [])
|
self.assertListEqual(list(data3[0].owner.groups.all()), [])
|
||||||
|
|
||||||
with self.assertNumQueries(
|
with self.assertNumQueries(
|
||||||
8 if self.is_sqlite and DJANGO_VERSION[0] == 2 and DJANGO_VERSION[1] == 2
|
8 if self.is_postgresql and DJANGO_VERSION >= (4, 2)
|
||||||
else 4 if self.is_postgresql and DJANGO_VERSION[0] > 2
|
else 4 if self.is_postgresql and DJANGO_VERSION >= (3, 0)
|
||||||
else 4 if self.is_mysql and DJANGO_VERSION[0] > 2
|
else 4 if self.is_mysql and DJANGO_VERSION >= (3, 0)
|
||||||
else 6
|
else 6
|
||||||
):
|
):
|
||||||
group = Group.objects.create(name='test_group')
|
group = Group.objects.create(name='test_group')
|
||||||
|
|
@ -694,7 +718,7 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
|
|
||||||
@skipUnlessDBFeature('has_select_for_update')
|
@skipUnlessDBFeature('has_select_for_update')
|
||||||
def test_invalidate_select_for_update(self):
|
def test_invalidate_select_for_update(self):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(3 if DJANGO_VERSION >= (4, 2) else 1):
|
||||||
Test.objects.bulk_create([Test(name='test1'), Test(name='test2')])
|
Test.objects.bulk_create([Test(name='test1'), Test(name='test2')])
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
|
|
@ -852,7 +876,9 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
|
||||||
with self.assertRaises(TestChild.DoesNotExist):
|
with self.assertRaises(TestChild.DoesNotExist):
|
||||||
TestChild.objects.get()
|
TestChild.objects.get()
|
||||||
|
|
||||||
with self.assertNumQueries(3 if self.is_sqlite else 2):
|
with self.assertNumQueries(
|
||||||
|
3 if self.is_sqlite else (4 if DJANGO_VERSION >= (4, 2) else 2)
|
||||||
|
):
|
||||||
t_child = TestChild.objects.create(name='test_child')
|
t_child = TestChild.objects.create(name='test_child')
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
|
|
|
||||||
5
tox.ini
5
tox.ini
|
|
@ -3,7 +3,7 @@ envlist =
|
||||||
py{37,38,39,310}-django3.2-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
py{37,38,39,310}-django3.2-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
||||||
py{38,39,310}-django4.1-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
py{38,39,310}-django4.1-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
||||||
py{38,39,310,311}-django4.2-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
py{38,39,310,311}-django4.2-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
||||||
py{38,39,310}-djangomain-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
py{38,39,310,311}-djangomain-{sqlite3,postgresql,mysql}-{redis,memcached,pylibmc,locmem,filebased},
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
passenv = *
|
passenv = *
|
||||||
|
|
@ -14,12 +14,11 @@ basepython =
|
||||||
py310: python3.10
|
py310: python3.10
|
||||||
py311: python3.11
|
py311: python3.11
|
||||||
deps =
|
deps =
|
||||||
django2.2: Django>=2.2,<2.3
|
|
||||||
django3.2: Django>=3.2,<4.0
|
django3.2: Django>=3.2,<4.0
|
||||||
django4.1: Django>=4.1,<4.2
|
django4.1: Django>=4.1,<4.2
|
||||||
django4.2: Django>=4.2,<4.3
|
django4.2: Django>=4.2,<4.3
|
||||||
djangomain: https://github.com/django/django/archive/main.tar.gz
|
djangomain: https://github.com/django/django/archive/main.tar.gz
|
||||||
psycopg2>=2.8,<2.9
|
psycopg2>=2.9.5,<3.0
|
||||||
psycopg
|
psycopg
|
||||||
mysqlclient
|
mysqlclient
|
||||||
django-redis
|
django-redis
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue