Correct problems with tests (#234)

This commit is contained in:
Jack Linke 2023-05-24 21:35:03 -04:00 committed by GitHub
parent b2d9de2997
commit 27eaaa57cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 115 additions and 87 deletions

View file

@ -4,14 +4,20 @@ Whats 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

View file

@ -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)

View file

@ -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):

View file

@ -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):

View file

@ -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:

View file

@ -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')

View file

@ -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:

View file

@ -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 doesnt decrease because update_or_create # The number of SQL queries doesnt decrease because update_or_create
# always calls an UPDATE, even when data wasnt changed. # always calls an UPDATE, even when data wasnt 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):

View file

@ -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