Fixed #32178 -- Allowed database backends to skip tests and mark expected failures.

Co-authored-by: Tim Graham <timograham@gmail.com>
This commit is contained in:
Hasan Ramezani 2020-12-10 18:00:57 +01:00 committed by GitHub
parent 5ce31d6a71
commit 275dd4ebba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 248 additions and 87 deletions

View File

@ -24,3 +24,17 @@ class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
def supports_geometry_field_unique_index(self): def supports_geometry_field_unique_index(self):
# Not supported in MySQL since https://dev.mysql.com/worklog/task/?id=11808 # Not supported in MySQL since https://dev.mysql.com/worklog/task/?id=11808
return self.connection.mysql_is_mariadb return self.connection.mysql_is_mariadb
@cached_property
def django_test_skips(self):
skips = super().django_test_skips
if (
not self.connection.mysql_is_mariadb and
self.connection.mysql_version < (8, 0, 0)
):
skips.update({
'MySQL < 8 gives different results.': {
'gis_tests.geoapp.tests.GeoLookupTest.test_disjoint_lookup',
},
})
return skips

View File

@ -12,3 +12,13 @@ class DatabaseFeatures(BaseSpatialFeatures, SQLiteDatabaseFeatures):
@cached_property @cached_property
def supports_area_geodetic(self): def supports_area_geodetic(self):
return bool(self.connection.ops.lwgeom_version()) return bool(self.connection.ops.lwgeom_version())
@cached_property
def django_test_skips(self):
skips = super().django_test_skips
skips.update({
"SpatiaLite doesn't support distance lookups with Distance objects.": {
'gis_tests.geogapp.tests.GeographyTest.test02_distance_lookup',
},
})
return skips

View File

@ -1,12 +1,14 @@
import os import os
import sys import sys
from io import StringIO from io import StringIO
from unittest import expectedFailure, skip
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core import serializers from django.core import serializers
from django.db import router from django.db import router
from django.db.transaction import atomic from django.db.transaction import atomic
from django.utils.module_loading import import_string
# The prefix to put on the default database name when creating # The prefix to put on the default database name when creating
# the test database. # the test database.
@ -92,6 +94,9 @@ class BaseDatabaseCreation:
# Ensure a connection for the side effect of initializing the test database. # Ensure a connection for the side effect of initializing the test database.
self.connection.ensure_connection() self.connection.ensure_connection()
if os.environ.get('RUNNING_DJANGOS_TEST_SUITE') == 'true':
self.mark_expected_failures_and_skips()
return test_database_name return test_database_name
def set_as_test_mirror(self, primary_settings_dict): def set_as_test_mirror(self, primary_settings_dict):
@ -293,6 +298,29 @@ class BaseDatabaseCreation:
cursor.execute("DROP DATABASE %s" cursor.execute("DROP DATABASE %s"
% self.connection.ops.quote_name(test_database_name)) % self.connection.ops.quote_name(test_database_name))
def mark_expected_failures_and_skips(self):
"""
Mark tests in Django's test suite which are expected failures on this
database and test which should be skipped on this database.
"""
for test_name in self.connection.features.django_test_expected_failures:
test_case_name, _, test_method_name = test_name.rpartition('.')
test_app = test_name.split('.')[0]
# Importing a test app that isn't installed raises RuntimeError.
if test_app in settings.INSTALLED_APPS:
test_case = import_string(test_case_name)
test_method = getattr(test_case, test_method_name)
setattr(test_case, test_method_name, expectedFailure(test_method))
for reason, tests in self.connection.features.django_test_skips.items():
for test_name in tests:
test_case_name, _, test_method_name = test_name.rpartition('.')
test_app = test_name.split('.')[0]
# Importing a test app that isn't installed raises RuntimeError.
if test_app in settings.INSTALLED_APPS:
test_case = import_string(test_case_name)
test_method = getattr(test_case, test_method_name)
setattr(test_case, test_method_name, skip(reason)(test_method))
def sql_table_creation_suffix(self): def sql_table_creation_suffix(self):
""" """
SQL to append to the end of the test table creation statements. SQL to append to the end of the test table creation statements.

View File

@ -323,6 +323,13 @@ class BaseDatabaseFeatures:
'swedish_ci': None # Swedish case-insensitive. 'swedish_ci': None # Swedish case-insensitive.
} }
# A set of dotted paths to tests in Django's test suite that are expected
# to fail on this database.
django_test_expected_failures = {}
# A map of reasons to sets of dotted paths to tests in Django's test suite
# that should be skipped for this database.
django_test_skips = {}
def __init__(self, connection): def __init__(self, connection):
self.connection = connection self.connection = connection

View File

@ -50,6 +50,52 @@ class DatabaseFeatures(BaseDatabaseFeatures):
'swedish_ci': 'utf8_swedish_ci', 'swedish_ci': 'utf8_swedish_ci',
} }
@cached_property
def django_test_skips(self):
skips = {
"This doesn't work on MySQL.": {
'db_functions.comparison.test_greatest.GreatestTests.test_coalesce_workaround',
'db_functions.comparison.test_least.LeastTests.test_coalesce_workaround',
},
'Running on MySQL requires utf8mb4 encoding (#18392).': {
'model_fields.test_textfield.TextFieldTests.test_emoji',
'model_fields.test_charfield.TestCharField.test_emoji',
},
}
if 'ONLY_FULL_GROUP_BY' in self.connection.sql_mode:
skips.update({
'GROUP BY optimization does not work properly when '
'ONLY_FULL_GROUP_BY mode is enabled on MySQL, see #31331.': {
'aggregation.tests.AggregateTestCase.test_aggregation_subquery_annotation_multivalued',
'annotations.tests.NonAggregateAnnotationTestCase.test_annotation_aggregate_with_m2o',
},
})
if (
self.connection.mysql_is_mariadb and
(10, 4, 3) < self.connection.mysql_version < (10, 5, 2)
):
skips.update({
'https://jira.mariadb.org/browse/MDEV-19598': {
'schema.tests.SchemaTests.test_alter_not_unique_field_to_primary_key',
},
})
if (
self.connection.mysql_is_mariadb and
(10, 4, 12) < self.connection.mysql_version < (10, 5)
):
skips.update({
'https://jira.mariadb.org/browse/MDEV-22775': {
'schema.tests.SchemaTests.test_alter_pk_with_self_referential_field',
},
})
if not self.supports_explain_analyze:
skips.update({
'MariaDB and MySQL >= 8.0.18 specific.': {
'queries.test_explain.ExplainTests.test_mysql_analyze',
},
})
return skips
@cached_property @cached_property
def _mysql_storage_engine(self): def _mysql_storage_engine(self):
"Internal method used in Django tests. Don't rely on this from your code" "Internal method used in Django tests. Don't rely on this from your code"

View File

@ -72,6 +72,28 @@ class DatabaseFeatures(BaseDatabaseFeatures):
'swedish_ci': 'SWEDISH_CI', 'swedish_ci': 'SWEDISH_CI',
} }
django_test_skips = {
"Oracle doesn't support SHA224.": {
'db_functions.text.test_sha224.SHA224Tests.test_basic',
'db_functions.text.test_sha224.SHA224Tests.test_transform',
},
"Oracle doesn't support bitwise XOR.": {
'expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor',
'expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null',
},
"Oracle requires ORDER BY in row_number, ANSI:SQL doesn't.": {
'expressions_window.tests.WindowFunctionTests.test_row_number_no_ordering',
},
'Raises ORA-00600: internal error code on Oracle 18.': {
'model_fields.test_jsonfield.TestQuerying.test_usage_in_subquery',
},
}
django_test_expected_failures = {
# A bug in Django/cx_Oracle with respect to string handling (#23843).
'annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions',
'annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions_can_ref_other_functions',
}
@cached_property @cached_property
def introspected_field_types(self): def introspected_field_types(self):
return { return {

View File

@ -59,6 +59,12 @@ class DatabaseFeatures(BaseDatabaseFeatures):
has_json_operators = True has_json_operators = True
json_key_contains_list_matching_requires_list = True json_key_contains_list_matching_requires_list = True
django_test_skips = {
'opclasses are PostgreSQL only.': {
'indexes.tests.SchemaIndexesNotPostgreSQLTests.test_create_index_ignores_opclasses',
},
}
@cached_property @cached_property
def test_collations(self): def test_collations(self):
# PostgreSQL < 10 doesn't support ICU collations. # PostgreSQL < 10 doesn't support ICU collations.

View File

@ -50,6 +50,37 @@ class DatabaseFeatures(BaseDatabaseFeatures):
'non_default': 'nocase', 'non_default': 'nocase',
} }
@cached_property
def django_test_skips(self):
skips = {
'SQLite stores values rounded to 15 significant digits.': {
'model_fields.test_decimalfield.DecimalFieldTests.test_fetch_from_db_without_float_rounding',
},
'SQLite naively remakes the table on field alteration.': {
'schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops',
'schema.tests.SchemaTests.test_unique_and_reverse_m2m',
'schema.tests.SchemaTests.test_alter_field_default_doesnt_perform_queries',
'schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references',
},
"SQLite doesn't have a constraint.": {
'model_fields.test_integerfield.PositiveIntegerFieldTests.test_negative_values',
},
}
if Database.sqlite_version_info < (3, 27):
skips.update({
'Nondeterministic failure on SQLite < 3.27.': {
'expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank',
},
})
if self.connection.is_in_memory_db():
skips.update({
"the sqlite backend's close() method is a no-op when using an "
"in-memory database": {
'servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections',
},
})
return skips
@cached_property @cached_property
def supports_atomic_references_rename(self): def supports_atomic_references_rename(self):
# SQLite 3.28.0 bundled with MacOS 10.15 does not support renaming # SQLite 3.28.0 bundled with MacOS 10.15 does not support renaming

View File

@ -197,6 +197,14 @@ CSRF
* ... * ...
Database backends
~~~~~~~~~~~~~~~~~
* Third-party database backends can now skip or mark as expected failures
tests in Django's test suite using the new
``DatabaseFeatures.django_test_skips`` and
``django_test_expected_failures`` attributes.
Decorators Decorators
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -1218,11 +1218,6 @@ class AggregateTestCase(TestCase):
Subquery annotations must be included in the GROUP BY if they use Subquery annotations must be included in the GROUP BY if they use
potentially multivalued relations (contain the LOOKUP_SEP). potentially multivalued relations (contain the LOOKUP_SEP).
""" """
if connection.vendor == 'mysql' and 'ONLY_FULL_GROUP_BY' in connection.sql_mode:
self.skipTest(
'GROUP BY optimization does not work properly when '
'ONLY_FULL_GROUP_BY mode is enabled on MySQL, see #31331.'
)
subquery_qs = Author.objects.filter( subquery_qs = Author.objects.filter(
pk=OuterRef('pk'), pk=OuterRef('pk'),
book__name=OuterRef('book__name'), book__name=OuterRef('book__name'),

View File

@ -2,7 +2,6 @@ import datetime
from decimal import Decimal from decimal import Decimal
from django.core.exceptions import FieldDoesNotExist, FieldError from django.core.exceptions import FieldDoesNotExist, FieldError
from django.db import connection
from django.db.models import ( from django.db.models import (
BooleanField, Case, CharField, Count, DateTimeField, DecimalField, Exists, BooleanField, Case, CharField, Count, DateTimeField, DecimalField, Exists,
ExpressionWrapper, F, FloatField, Func, IntegerField, Max, ExpressionWrapper, F, FloatField, Func, IntegerField, Max,
@ -20,19 +19,6 @@ from .models import (
) )
def cxOracle_py3_bug(func):
"""
There's a bug in Django/cx_Oracle with respect to string handling under
Python 3 (essentially, they treat Python 3 strings as Python 2 strings
rather than unicode). This makes some tests here fail under Python 3, so
we mark them as expected failures until someone fixes them in #23843.
"""
from unittest import expectedFailure
from django.db import connection
return expectedFailure(func) if connection.vendor == 'oracle' else func
class NonAggregateAnnotationTestCase(TestCase): class NonAggregateAnnotationTestCase(TestCase):
@classmethod @classmethod
@ -590,7 +576,6 @@ class NonAggregateAnnotationTestCase(TestCase):
e.id, e.first_name, e.manager, e.random_value, e.last_name, e.age, e.id, e.first_name, e.manager, e.random_value, e.last_name, e.age,
e.salary, e.store.name, e.annotated_value)) e.salary, e.store.name, e.annotated_value))
@cxOracle_py3_bug
def test_custom_functions(self): def test_custom_functions(self):
Company(name='Apple', motto=None, ticker_name='APPL', description='Beautiful Devices').save() Company(name='Apple', motto=None, ticker_name='APPL', description='Beautiful Devices').save()
Company(name='Django Software Foundation', motto=None, ticker_name=None, description=None).save() Company(name='Django Software Foundation', motto=None, ticker_name=None, description=None).save()
@ -617,7 +602,6 @@ class NonAggregateAnnotationTestCase(TestCase):
lambda c: (c.name, c.tagline) lambda c: (c.name, c.tagline)
) )
@cxOracle_py3_bug
def test_custom_functions_can_ref_other_functions(self): def test_custom_functions_can_ref_other_functions(self):
Company(name='Apple', motto=None, ticker_name='APPL', description='Beautiful Devices').save() Company(name='Apple', motto=None, ticker_name='APPL', description='Beautiful Devices').save()
Company(name='Django Software Foundation', motto=None, ticker_name=None, description=None).save() Company(name='Django Software Foundation', motto=None, ticker_name=None, description=None).save()
@ -770,11 +754,6 @@ class NonAggregateAnnotationTestCase(TestCase):
]) ])
def test_annotation_aggregate_with_m2o(self): def test_annotation_aggregate_with_m2o(self):
if connection.vendor == 'mysql' and 'ONLY_FULL_GROUP_BY' in connection.sql_mode:
self.skipTest(
'GROUP BY optimization does not work properly when '
'ONLY_FULL_GROUP_BY mode is enabled on MySQL, see #31331.'
)
qs = Author.objects.filter(age__lt=30).annotate( qs = Author.objects.filter(age__lt=30).annotate(
max_pages=Case( max_pages=Case(
When(book_contact_set__isnull=True, then=Value(0)), When(book_contact_set__isnull=True, then=Value(0)),

View File

@ -1,5 +1,6 @@
import copy import copy
import datetime import datetime
import os
from unittest import mock from unittest import mock
from django.db import DEFAULT_DB_ALIAS, connection, connections from django.db import DEFAULT_DB_ALIAS, connection, connections
@ -107,6 +108,22 @@ class TestDbCreationTests(SimpleTestCase):
with mock.patch.object(creation, '_destroy_test_db'): with mock.patch.object(creation, '_destroy_test_db'):
creation.destroy_test_db(old_database_name, verbosity=0) creation.destroy_test_db(old_database_name, verbosity=0)
@mock.patch.dict(os.environ, {'RUNNING_DJANGOS_TEST_SUITE': ''})
@mock.patch.object(BaseDatabaseCreation, 'mark_expected_failures_and_skips')
def test_mark_expected_failures_and_skips_call(self, mark_expected_failures_and_skips, *mocked_objects):
"""
mark_expected_failures_and_skips() isn't called unless
RUNNING_DJANGOS_TEST_SUITE is 'true'.
"""
test_connection = get_connection_copy()
creation = test_connection.creation_class(test_connection)
if connection.vendor == 'oracle':
# Don't close connection on Oracle.
creation.connection.close = mock.Mock()
with mock.patch.object(creation, '_create_test_db'):
creation.create_test_db(verbosity=0, autoclobber=True, serialize=False)
self.assertIs(mark_expected_failures_and_skips.called, False)
class TestDeserializeDbFromString(TransactionTestCase): class TestDeserializeDbFromString(TransactionTestCase):
available_apps = ['backends'] available_apps = ['backends']
@ -188,3 +205,48 @@ class TestDeserializeDbFromString(TransactionTestCase):
data = connection.creation.serialize_db_to_string() data = connection.creation.serialize_db_to_string()
self.assertIn('"model": "backends.schoolclass"', data) self.assertIn('"model": "backends.schoolclass"', data)
self.assertIn('"year": 1000', data) self.assertIn('"year": 1000', data)
class SkipTestClass:
def skip_function(self):
pass
def skip_test_function():
pass
def expected_failure_test_function():
pass
class TestMarkTests(SimpleTestCase):
def test_mark_expected_failures_and_skips(self):
test_connection = get_connection_copy()
creation = BaseDatabaseCreation(test_connection)
creation.connection.features.django_test_expected_failures = {
'backends.base.test_creation.expected_failure_test_function',
}
creation.connection.features.django_test_skips = {
'skip test class': {
'backends.base.test_creation.SkipTestClass',
},
'skip test function': {
'backends.base.test_creation.skip_test_function',
},
}
creation.mark_expected_failures_and_skips()
self.assertIs(
expected_failure_test_function.__unittest_expecting_failure__,
True,
)
self.assertIs(SkipTestClass.__unittest_skip__, True)
self.assertEqual(
SkipTestClass.__unittest_skip_why__,
'skip test class',
)
self.assertIs(skip_test_function.__unittest_skip__, True)
self.assertEqual(
skip_test_function.__unittest_skip_why__,
'skip test function',
)

View File

@ -1,6 +1,6 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from decimal import Decimal from decimal import Decimal
from unittest import skipIf, skipUnless from unittest import skipUnless
from django.db import connection from django.db import connection
from django.db.models.expressions import RawSQL from django.db.models.expressions import RawSQL
@ -33,7 +33,6 @@ class GreatestTests(TestCase):
articles = Article.objects.annotate(last_updated=Greatest('written', 'published')) articles = Article.objects.annotate(last_updated=Greatest('written', 'published'))
self.assertIsNone(articles.first().last_updated) self.assertIsNone(articles.first().last_updated)
@skipIf(connection.vendor == 'mysql', "This doesn't work on MySQL")
def test_coalesce_workaround(self): def test_coalesce_workaround(self):
past = datetime(1900, 1, 1) past = datetime(1900, 1, 1)
now = timezone.now() now = timezone.now()

View File

@ -1,6 +1,6 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from decimal import Decimal from decimal import Decimal
from unittest import skipIf, skipUnless from unittest import skipUnless
from django.db import connection from django.db import connection
from django.db.models.expressions import RawSQL from django.db.models.expressions import RawSQL
@ -35,7 +35,6 @@ class LeastTests(TestCase):
articles = Article.objects.annotate(first_updated=Least('written', 'published')) articles = Article.objects.annotate(first_updated=Least('written', 'published'))
self.assertIsNone(articles.first().first_updated) self.assertIsNone(articles.first().first_updated)
@skipIf(connection.vendor == 'mysql', "This doesn't work on MySQL")
def test_coalesce_workaround(self): def test_coalesce_workaround(self):
future = datetime(2100, 1, 1) future = datetime(2100, 1, 1)
now = timezone.now() now = timezone.now()

View File

@ -20,7 +20,6 @@ class SHA224Tests(TestCase):
Author(alias=None), Author(alias=None),
]) ])
@unittest.skipIf(connection.vendor == 'oracle', "Oracle doesn't support SHA224.")
def test_basic(self): def test_basic(self):
authors = Author.objects.annotate( authors = Author.objects.annotate(
sha224_alias=SHA224('alias'), sha224_alias=SHA224('alias'),
@ -37,7 +36,6 @@ class SHA224Tests(TestCase):
], ],
) )
@unittest.skipIf(connection.vendor == 'oracle', "Oracle doesn't support SHA224.")
def test_transform(self): def test_transform(self):
with register_lookup(CharField, SHA224): with register_lookup(CharField, SHA224):
authors = Author.objects.filter( authors = Author.objects.filter(

View File

@ -1230,13 +1230,11 @@ class ExpressionOperatorTests(TestCase):
self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 1764) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 1764)
self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(61.02, places=2)) self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(61.02, places=2))
@unittest.skipIf(connection.vendor == 'oracle', "Oracle doesn't support bitwise XOR.")
def test_lefthand_bitwise_xor(self): def test_lefthand_bitwise_xor(self):
Number.objects.update(integer=F('integer').bitxor(48)) Number.objects.update(integer=F('integer').bitxor(48))
self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 26) self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 26)
self.assertEqual(Number.objects.get(pk=self.n1.pk).integer, -26) self.assertEqual(Number.objects.get(pk=self.n1.pk).integer, -26)
@unittest.skipIf(connection.vendor == 'oracle', "Oracle doesn't support bitwise XOR.")
def test_lefthand_bitwise_xor_null(self): def test_lefthand_bitwise_xor_null(self):
employee = Employee.objects.create(firstname='John', lastname='Doe') employee = Employee.objects.create(firstname='John', lastname='Doe')
Employee.objects.update(salary=F('salary').bitxor(48)) Employee.objects.update(salary=F('salary').bitxor(48))

View File

@ -1,6 +1,6 @@
import datetime import datetime
from decimal import Decimal from decimal import Decimal
from unittest import mock, skipIf from unittest import mock
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.db import NotSupportedError, connection from django.db import NotSupportedError, connection
@ -150,7 +150,6 @@ class WindowFunctionTests(TestCase):
('Johnson', 'Management', 12), ('Johnson', 'Management', 12),
], lambda entry: (entry.name, entry.department, entry.row_number)) ], lambda entry: (entry.name, entry.department, entry.row_number))
@skipIf(connection.vendor == 'oracle', "Oracle requires ORDER BY in row_number, ANSI:SQL doesn't")
def test_row_number_no_ordering(self): def test_row_number_no_ordering(self):
""" """
The row number window function computes the number based on the order The row number window function computes the number based on the order
@ -633,10 +632,6 @@ class WindowFunctionTests(TestCase):
('Brown', 'Sales', 53000, datetime.date(2009, 9, 1), 148000) ('Brown', 'Sales', 53000, datetime.date(2009, 9, 1), 148000)
], transform=lambda row: (row.name, row.department, row.salary, row.hire_date, row.sum)) ], transform=lambda row: (row.name, row.department, row.salary, row.hire_date, row.sum))
@skipIf(
connection.vendor == 'sqlite' and connection.Database.sqlite_version_info < (3, 27),
'Nondeterministic failure on SQLite < 3.27.'
)
def test_subquery_row_range_rank(self): def test_subquery_row_range_rank(self):
qs = Employee.objects.annotate( qs = Employee.objects.annotate(
highest_avg_salary_date=Subquery( highest_avg_salary_date=Subquery(

View File

@ -1,5 +1,4 @@
import tempfile import tempfile
import unittest
from io import StringIO from io import StringIO
from django.contrib.gis import gdal from django.contrib.gis import gdal
@ -229,8 +228,6 @@ class GeoLookupTest(TestCase):
def test_disjoint_lookup(self): def test_disjoint_lookup(self):
"Testing the `disjoint` lookup type." "Testing the `disjoint` lookup type."
if mysql and not mariadb and connection.mysql_version < (8, 0, 0):
raise unittest.SkipTest('MySQL < 8 gives different results.')
ptown = City.objects.get(name='Pueblo') ptown = City.objects.get(name='Pueblo')
qs1 = City.objects.filter(point__disjoint=ptown.point) qs1 = City.objects.filter(point__disjoint=ptown.point)
self.assertEqual(7, qs1.count()) self.assertEqual(7, qs1.count())

View File

@ -2,7 +2,7 @@
Tests for geography support in PostGIS Tests for geography support in PostGIS
""" """
import os import os
from unittest import skipIf, skipUnless from unittest import skipUnless
from django.contrib.gis.db import models from django.contrib.gis.db import models
from django.contrib.gis.db.models.functions import Area, Distance from django.contrib.gis.db.models.functions import Area, Distance
@ -22,7 +22,6 @@ class GeographyTest(TestCase):
"Ensure geography features loaded properly." "Ensure geography features loaded properly."
self.assertEqual(8, City.objects.count()) self.assertEqual(8, City.objects.count())
@skipIf(spatialite, "SpatiaLite doesn't support distance lookups with Distance objects.")
@skipUnlessDBFeature("supports_distances_lookups", "supports_distance_geodetic") @skipUnlessDBFeature("supports_distances_lookups", "supports_distance_geodetic")
def test02_distance_lookup(self): def test02_distance_lookup(self):
"Testing distance lookup support on non-point geography fields." "Testing distance lookup support on non-point geography fields."

View File

@ -1,5 +1,5 @@
import datetime import datetime
from unittest import skipIf, skipUnless from unittest import skipUnless
from django.db import connection from django.db import connection
from django.db.models import CASCADE, ForeignKey, Index, Q from django.db.models import CASCADE, ForeignKey, Index, Q
@ -89,7 +89,6 @@ class SchemaIndexesTests(TestCase):
) )
@skipIf(connection.vendor == 'postgresql', 'opclasses are PostgreSQL only')
class SchemaIndexesNotPostgreSQLTests(TransactionTestCase): class SchemaIndexesNotPostgreSQLTests(TransactionTestCase):
available_apps = ['indexes'] available_apps = ['indexes']

View File

@ -1,7 +1,5 @@
from unittest import skipIf
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import connection, models from django.db import models
from django.test import SimpleTestCase, TestCase from django.test import SimpleTestCase, TestCase
from .models import Post from .models import Post
@ -22,7 +20,6 @@ class TestCharField(TestCase):
def test_lookup_integer_in_charfield(self): def test_lookup_integer_in_charfield(self):
self.assertEqual(Post.objects.filter(title=9).count(), 0) self.assertEqual(Post.objects.filter(title=9).count(), 0)
@skipIf(connection.vendor == 'mysql', 'Running on MySQL requires utf8mb4 encoding (#18392)')
def test_emoji(self): def test_emoji(self):
p = Post.objects.create(title='Smile 😀', body='Whatever.') p = Post.objects.create(title='Smile 😀', body='Whatever.')
p.refresh_from_db() p.refresh_from_db()

View File

@ -1,9 +1,8 @@
import unittest
from decimal import Decimal from decimal import Decimal
from django.core import validators from django.core import validators
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import connection, models from django.db import models
from django.test import TestCase from django.test import TestCase
from .models import BigD, Foo from .models import BigD, Foo
@ -66,7 +65,6 @@ class DecimalFieldTests(TestCase):
bd = BigD.objects.get(pk=bd.pk) bd = BigD.objects.get(pk=bd.pk)
self.assertEqual(bd.d, Decimal('12.9')) self.assertEqual(bd.d, Decimal('12.9'))
@unittest.skipIf(connection.vendor == 'sqlite', 'SQLite stores values rounded to 15 significant digits.')
def test_fetch_from_db_without_float_rounding(self): def test_fetch_from_db_without_float_rounding(self):
big_decimal = BigD.objects.create(d=Decimal('.100000000000000000000000000005')) big_decimal = BigD.objects.create(d=Decimal('.100000000000000000000000000005'))
big_decimal.refresh_from_db() big_decimal.refresh_from_db()

View File

@ -1,5 +1,3 @@
import unittest
from django.core import validators from django.core import validators
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import IntegrityError, connection, models from django.db import IntegrityError, connection, models
@ -192,7 +190,6 @@ class PositiveIntegerFieldTests(IntegerFieldTests):
else models.IntegerField else models.IntegerField
) )
@unittest.skipIf(connection.vendor == 'sqlite', "SQLite doesn't have a constraint.")
def test_negative_values(self): def test_negative_values(self):
p = PositiveIntegerModel.objects.create(value=0) p = PositiveIntegerModel.objects.create(value=0)
p.value = models.F('value') - 1 p.value = models.F('value') - 1

View File

@ -1,6 +1,6 @@
import operator import operator
import uuid import uuid
from unittest import mock, skipIf from unittest import mock
from django import forms from django import forms
from django.core import serializers from django.core import serializers
@ -719,10 +719,6 @@ class TestQuerying(TestCase):
objs_with_value, objs_with_value,
) )
@skipIf(
connection.vendor == 'oracle',
'Raises ORA-00600: internal error code on Oracle 18.',
)
def test_usage_in_subquery(self): def test_usage_in_subquery(self):
self.assertSequenceEqual( self.assertSequenceEqual(
NullableJSONModel.objects.filter( NullableJSONModel.objects.filter(

View File

@ -1,7 +1,5 @@
from unittest import skipIf
from django import forms from django import forms
from django.db import connection, models from django.db import models
from django.test import SimpleTestCase, TestCase from django.test import SimpleTestCase, TestCase
from .models import Post from .models import Post
@ -32,7 +30,6 @@ class TextFieldTests(TestCase):
def test_lookup_integer_in_textfield(self): def test_lookup_integer_in_textfield(self):
self.assertEqual(Post.objects.filter(body=24).count(), 0) self.assertEqual(Post.objects.filter(body=24).count(), 0)
@skipIf(connection.vendor == 'mysql', 'Running on MySQL requires utf8mb4 encoding (#18392)')
def test_emoji(self): def test_emoji(self):
p = Post.objects.create(title='Whatever', body='Smile 😀.') p = Post.objects.create(title='Whatever', body='Smile 😀.')
p.refresh_from_db() p.refresh_from_db()

View File

@ -80,9 +80,6 @@ class ExplainTests(TestCase):
@unittest.skipUnless(connection.vendor == 'mysql', 'MariaDB and MySQL >= 8.0.18 specific.') @unittest.skipUnless(connection.vendor == 'mysql', 'MariaDB and MySQL >= 8.0.18 specific.')
def test_mysql_analyze(self): def test_mysql_analyze(self):
# Inner skip to avoid module level query for MySQL version.
if not connection.features.supports_explain_analyze:
raise unittest.SkipTest('MariaDB and MySQL >= 8.0.18 specific.')
qs = Tag.objects.filter(name='test') qs = Tag.objects.filter(name='test')
with CaptureQueriesContext(connection) as captured_queries: with CaptureQueriesContext(connection) as captured_queries:
qs.explain(analyze=True) qs.explain(analyze=True)

View File

@ -254,6 +254,10 @@ def setup(verbosity, test_labels, parallel, start_at, start_after):
apps.set_installed_apps(settings.INSTALLED_APPS) apps.set_installed_apps(settings.INSTALLED_APPS)
# Set an environment variable that other code may consult to see if
# Django's own test suite is running.
os.environ['RUNNING_DJANGOS_TEST_SUITE'] = 'true'
return state return state
@ -267,6 +271,7 @@ def teardown(state):
# FileNotFoundError at the end of a test run (#27890). # FileNotFoundError at the end of a test run (#27890).
from multiprocessing.util import _finalizer_registry from multiprocessing.util import _finalizer_registry
_finalizer_registry.pop((-100, 0), None) _finalizer_registry.pop((-100, 0), None)
del os.environ['RUNNING_DJANGOS_TEST_SUITE']
def actual_test_processes(parallel): def actual_test_processes(parallel):

View File

@ -729,12 +729,6 @@ class SchemaTests(TransactionTestCase):
Foo.objects.create() Foo.objects.create()
def test_alter_not_unique_field_to_primary_key(self): def test_alter_not_unique_field_to_primary_key(self):
if (
connection.vendor == 'mysql' and
connection.mysql_is_mariadb and
(10, 4, 3) < connection.mysql_version < (10, 5, 2)
):
self.skipTest('https://jira.mariadb.org/browse/MDEV-19598')
# Create the table. # Create the table.
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
editor.create_model(Author) editor.create_model(Author)
@ -1957,7 +1951,6 @@ class SchemaTests(TransactionTestCase):
TagUniqueRename._meta.db_table = old_table_name TagUniqueRename._meta.db_table = old_table_name
@isolate_apps('schema') @isolate_apps('schema')
@unittest.skipIf(connection.vendor == 'sqlite', 'SQLite naively remakes the table on field alteration.')
@skipUnlessDBFeature('supports_foreign_keys') @skipUnlessDBFeature('supports_foreign_keys')
def test_unique_no_unnecessary_fk_drops(self): def test_unique_no_unnecessary_fk_drops(self):
""" """
@ -1991,7 +1984,6 @@ class SchemaTests(TransactionTestCase):
self.assertEqual(len(cm.records), 1) self.assertEqual(len(cm.records), 1)
@isolate_apps('schema') @isolate_apps('schema')
@unittest.skipIf(connection.vendor == 'sqlite', 'SQLite remakes the table on field alteration.')
def test_unique_and_reverse_m2m(self): def test_unique_and_reverse_m2m(self):
""" """
AlterField can modify a unique field when there's a reverse M2M AlterField can modify a unique field when there's a reverse M2M
@ -2759,7 +2751,6 @@ class SchemaTests(TransactionTestCase):
if connection.features.can_introspect_default: if connection.features.can_introspect_default:
self.assertIsNone(field.default) self.assertIsNone(field.default)
@unittest.skipIf(connection.vendor == 'sqlite', 'SQLite naively remakes the table on field alteration.')
def test_alter_field_default_doesnt_perform_queries(self): def test_alter_field_default_doesnt_perform_queries(self):
""" """
No queries are performed if a field default changes and the field's No queries are performed if a field default changes and the field's
@ -3041,12 +3032,6 @@ class SchemaTests(TransactionTestCase):
Changing the primary key field name of a model with a self-referential Changing the primary key field name of a model with a self-referential
foreign key (#26384). foreign key (#26384).
""" """
if (
connection.vendor == 'mysql' and
connection.mysql_is_mariadb and
(10, 4, 12) < connection.mysql_version < (10, 5)
):
self.skipTest('https://jira.mariadb.org/browse/MDEV-22775')
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
editor.create_model(Node) editor.create_model(Node)
old_field = Node._meta.get_field('node_id') old_field = Node._meta.get_field('node_id')
@ -3203,7 +3188,6 @@ class SchemaTests(TransactionTestCase):
self.assertIs(statement.references_table('schema_author'), False) self.assertIs(statement.references_table('schema_author'), False)
self.assertIs(statement.references_table('schema_book'), False) self.assertIs(statement.references_table('schema_book'), False)
@unittest.skipIf(connection.vendor == 'sqlite', 'SQLite naively remakes the table on field alteration.')
def test_rename_column_renames_deferred_sql_references(self): def test_rename_column_renames_deferred_sql_references(self):
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
editor.create_model(Author) editor.create_model(Author)

View File

@ -13,8 +13,6 @@ class LiveServerThreadTest(TestCase):
def test_closes_connections(self): def test_closes_connections(self):
conn = connections[DEFAULT_DB_ALIAS] conn = connections[DEFAULT_DB_ALIAS]
if conn.vendor == 'sqlite' and conn.is_in_memory_db():
self.skipTest("the sqlite backend's close() method is a no-op when using an in-memory database")
# Pass a connection to the thread to check they are being closed. # Pass a connection to the thread to check they are being closed.
connections_override = {DEFAULT_DB_ALIAS: conn} connections_override = {DEFAULT_DB_ALIAS: conn}